package com.itlong.cloud.operate.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.DTO.operate.*;
import com.itlong.cloud.POJO.PO.*;
import com.itlong.cloud.POJO.VO.MessageVO;
import com.itlong.cloud.POJO.VO.operate.*;
import com.itlong.cloud.POJO.VO.property.PropertyRoleProjectGetVO;
import com.itlong.cloud.POJO.VO.property.PropertyTreeMenuVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RabbitMQConstant;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.*;
import com.itlong.cloud.enumerate.ecode.BaseErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.ErrorCode;
import com.itlong.cloud.enumerate.ecode.OperateErrorCodeEnum;
import com.itlong.cloud.operate.dao.IOperateProjectDao;
import com.itlong.cloud.operate.service.IOperateProjectService;
import com.itlong.cloud.rabbitmq.config.MessageSender;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.date.DateUtil;
import com.itlong.cloud.utils.encrypt.SmartCardEncryptUtil;
import com.itlong.cloud.utils.network.https.HttpsPost;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.IdWorker;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.NumberHandlerUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <desc>
 *      项目管理接口实现
 * </desc>
 *
 * @createDate 2017-10-10.
 */
@Service
@RefreshScope
public class OperateProjectServiceImpl implements IOperateProjectService{

    //云对讲业务服务器默认地址
    @Value("${" + PlatformConstants.CLOUD_INTERCOM_BUSINESS_SERVER_DEFAULT_URL + "}")
    String defaultBusinessServerUrl;

    //取消人脸信息配置中的人脸库为不是必填项所需的常量。
    @Value("${" + PlatformConstants.PM_DEFAULT_FACE_LIBRARY_APPID + "}")
    String appId;

    @Value("${" + PlatformConstants.PM_DEFAULT_FACE_LIBRARY_API_KEY + "}")
    String apiKey;

    @Value("${" + PlatformConstants.PM_DEFAULT_FACE_LIBRARY_SECRET_KEY + "}")
    String secretKey;

    @Value("${" + PlatformConstants.PROJECT_LICENSE_VERSION + "}")
    String licenseVersion;

    @Value("${" + PlatformConstants.OFFLINE_PLATFORM_TOKEN + "}")
    String offlinePlatformToken;

    @Value("${" + PlatformConstants.OFFLINE_PLATFORM_DOMAIN + "}")
    private String offlinePLatformDomain;

    @Autowired
    private MessageSender messageSender;

    @Autowired
    private IOperateProjectDao iOperateProjectDao;

    @Autowired
    RedisService redisService;

    final static IdWorker idWorker = new IdWorker(18);
    //保存操作
    private final int SAVE_OPERATION = 1;
    //修改操作
    private final int UPDATE_OPERATION = 2;

    private static final int ENGINEER_LICENSE_AVAILABLE_DAYS = 15;


    /**
     * <desc>
     * 判断项目存在性
     * <desc/>
     *
     * @param projectId 项目编号
     * @return 同编号项目个数
     * @author Chunjian.G
     * @createDate 2017-10-27
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Integer checkProjectExist(String projectId) throws Exception {
        return iOperateProjectDao.checkProjectExist(projectId);
    }

    /**
     * <desc>
     * 添加单个项目
     * <desc/>
     *
     * @param saveDTO 项目新增信息
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-12
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer saveProject(OperateProjectSaveDTO saveDTO) throws Exception {

        //获取项目可用id
        String url  = offlinePLatformDomain + PlatformConstants.OFFLINE_PLATFORM_GET_PROJECTID_BY_TYPE;
        Map<String, Object> getProjectIdParams = new HashMap();
        if(saveDTO.getProductType() == null){
            throw new DataAccessException("【缺少必要参数】");
        }
        switch (saveDTO.getProductType()){
            case 0:
                getProjectIdParams.put("projectType", "0000");
                break;
            case 1:
                getProjectIdParams.put("projectType", "1001");
                break;
            case 2:
                getProjectIdParams.put("projectType", "3000");
                break;
            case 3:
                getProjectIdParams.put("projectType", "3100");
                break;
        }
        getProjectIdParams.put("token", offlinePlatformToken);

        String result = HttpsPost.doPost(url, getProjectIdParams, 20000, 20000);

        if (StringUtils.isBlank(result)) {
            throw new DataAccessException("【获取项目可用id失败】");
        }
        Map<String, Object> resultMap = JSONObject.parseObject(result, HashMap.class);
        if ("0".equals(resultMap.get("code") + "") && resultMap.get("data") != null) {
            saveDTO.setProjectId(JSONObject.parseObject(resultMap.get("data") + "", HashMap.class).get("projectId") + "");
        } else{
            throw new DataAccessException("【获取项目可用id失败】");
        }
//        saveDTO.setProjectId("0000"+(iOperateProjectDao.getMaxProjectId()+""));
        //定义返回值
        Integer res;
        //外部判断项目存在性
        ProjectPO projectPO = new ProjectPO();
        BeanUtils.copyProperties(saveDTO, projectPO);
        projectPO.setCommunityName(projectPO.getProjectName());
        //计算PubKey
//        IdWorker idWorker = new IdWorker(16);
        String str = (String.valueOf(Math.random()).substring(2,12) + System.currentTimeMillis()).substring(0, 16);
        String str1 = String.valueOf(idWorker.nextId()).substring(0, 16);
        String[] sourceContentArr = { "A", "B", "C", "D", "E", "F"};
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            int value = str.charAt(i) - '0';
            int value1 = str1.charAt(i) - '0';
            if (value % 2 == 0) {
                sb.append(value1);
            } else {
                if (value1 > 5) {
                    value1 = value1 - 5;
                }
                sb.append(sourceContentArr[value1]);
            }
        }
        projectPO.setPubKey(sb.toString());
        if (projectPO.getIsPrivateCloud() == null || projectPO.getIsPrivateCloud() == 0){
            //未启用私有云时使用默认云对讲业务服务器
            projectPO.setDeviceAddress(defaultBusinessServerUrl);
        }
        Date createTime = new Date();
        projectPO.setCreateTime(createTime);
        projectPO.setUpdateTime(createTime);
        projectPO.setCloudServiceCost(Integer.parseInt(saveDTO.getCloudServerCost()));
        Map<String, Object> params = SqlUtil.durableData(projectPO, PlatformConstants.TABLE_SAVE);
        res = iOperateProjectDao.save(params);
        if (res <= 0){
            throw new DataAccessException("【创建项目失败】");
        }

        //如果创建项目时所关联的任务书编号不为空，则需保存项目与任务收间的关系 operate_project_assignment_info
        if(StringUtils.isNotBlank(saveDTO.getAssignmentIds())){
            List<Map<String,Object>> batchParams = new ArrayList<>();
            String[] assignmentIdArr = saveDTO.getAssignmentIds().split(",");
            for(String assignmentId : assignmentIdArr){
                OperateProjectAssignmentInfoPO assignmentInfoPO = new OperateProjectAssignmentInfoPO();
                assignmentInfoPO.setRelationId(LogicIdUtil.bussinessId());
                assignmentInfoPO.setAssignmentId(assignmentId);
                assignmentInfoPO.setProjectId(projectPO.getProjectId());
                assignmentInfoPO.setCreateTime(new Date());
                assignmentInfoPO.setUpdateTime(new Date());
                assignmentInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
                batchParams.add(SqlUtil.durableData(assignmentInfoPO, PlatformConstants.TABLE_SAVE));
            }
            if(batchParams.size()>0){
                iOperateProjectDao.batchSaveProjectAssignment(batchParams);
            }
        }

        //记录操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateProjectDao.getUserInfo(saveDTO.getLoginUserId());
        OperationSpecialLogPO operationSpecialLogPO = handleSaveOperationLog(operateUserInfoPO);
//        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
//        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
//        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
//        operationSpecialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
        operationSpecialLogPO.setOuterId(projectPO.getProjectId());
        operationSpecialLogPO.setIp(saveDTO.getIp());
        operationSpecialLogPO.setOperateFunction(saveDTO.getOperateFunction());
        operationSpecialLogPO.setOperateWay(saveDTO.getOperateWay());
        operationSpecialLogPO.setOperateData(JSON.toJSONString(saveDTO));
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + "创建项目" + "项目ID：" + projectPO.getProjectId() + "，项目名称：" + projectPO.getProjectName() + "，项目属性：" + (projectPO.getProjectProperty().equals(0) ? "正式项目" : "非正式项目"));
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(createTime);
        operationSpecialLogPO.setUpdateTime(createTime);
        res = iOperateProjectDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));
        if (res <= 0){
            throw new DataAccessException("【创建项目失败】");
        }
        //同步ProjectKey到线下平台
        boolean resultProjectKey = pushProjectKeyToOffline(createTime, projectPO);

        //同步ProjectInfo到线下平台
        boolean resultProjectInfo = pushProjectInfoToOffline(SAVE_OPERATION, createTime, projectPO);
        if (resultProjectInfo && resultProjectKey && res > 0) {
            return res;
        } else {
            throw new DataAccessException("【创建项目失败】");
        }
    }

    /**
     * <desc>
     *      更新单个项目信息事务
     * <desc/>
     *
     * @param updateDTO 项目更新信息
     * @return
     * @author Chunjian.G
     * @createDate 2018-02-25
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Map<String, Object> updateProjectTrans(OperateProjectUpdateDTO updateDTO) throws Exception{
        Map<String, Object> resultMap = new HashMap<>();
        //更新前的项目信息
        ProjectPO oldProj = iOperateProjectDao.getOne(updateDTO.getProjectId());

        ProjectPO projectPO = new ProjectPO();
        BeanUtils.copyProperties(updateDTO, projectPO);

        if(updateDTO.getUpdateFlag()!=null && updateDTO.getUpdateFlag()==2){
            iOperateProjectDao.updateBluetoothThresholdByProjectId(updateDTO.getProjectId(),updateDTO.getBluetoothThreshold());
            return null;
        }

        if(updateDTO.getUpdateFlag()!=null && updateDTO.getUpdateFlag()==1){

            //场景变更，物业项目用户类型相关逻辑变更
            this.propertyProjectUserTypeData(updateDTO,oldProj);

            if(StringUtils.isNotBlank(updateDTO.getProjectSceneId())){
                projectPO.setSceneId(updateDTO.getProjectSceneId());
            }
            if(StringUtils.isNotBlank(updateDTO.getProjectPackageId())){
                iOperateProjectDao.deleteProjectAndPackage(updateDTO.getProjectId());
                iOperateProjectDao.allotPackageProject(updateDTO.getProjectPackageId(),
                        updateDTO.getProjectId(),
                        DataStatusEnum.NORMAL.getType(), new Date());
                //变更物业菜单
                //找出该套餐的菜单列表
                try{
                    List<String> functionList = iOperateProjectDao.getFunctionIds(updateDTO.getProjectPackageId());
                    List<String> oldFunctionIds = iOperateProjectDao.getFunctionByProjectId(updateDTO.getProjectId());
                    List<String> oldFunctionIdsCopy = new ArrayList<>(oldFunctionIds);
                    oldFunctionIds.removeAll(functionList);
                    //删除项目下所有用户应该被取消的菜单权限
                    if (!oldFunctionIds.isEmpty()){
                        Map<String, Object> deleteParams= new HashMap<>();
                        deleteParams.put("projectId", updateDTO.getProjectId());
                        deleteParams.put("functionIds", oldFunctionIds);
                        iOperateProjectDao.deleteUserFunctions(deleteParams);
                    }
                    //添加新权限
                    functionList.removeAll(oldFunctionIdsCopy);
                    if (!functionList.isEmpty()){
                        List<PropertyRoleFunctionPO> roleFunctionPOList = new ArrayList<>();
                        for (String functionId : functionList){
                            PropertyRoleFunctionPO roleFunctionPO = new PropertyRoleFunctionPO();
                            roleFunctionPO.setFunctionId(functionId);
                            roleFunctionPO.setProjectId(updateDTO.getProjectId());
                            roleFunctionPO.setRoleId(PropertyPublicRoleEnum.ADMIN.getRoleId());
                            roleFunctionPO.setStatus(DataStatusEnum.NORMAL.getType());
                            roleFunctionPO.setCreateTime(new Date());
                            roleFunctionPOList.add(roleFunctionPO);

                            PropertyRoleFunctionPO groupRoleFunctionPO = new PropertyRoleFunctionPO();
                            groupRoleFunctionPO.setFunctionId(functionId);
                            groupRoleFunctionPO.setProjectId(updateDTO.getProjectId());
                            groupRoleFunctionPO.setRoleId(PropertyPublicRoleEnum.GROUP_ADMIN.getRoleId());
                            groupRoleFunctionPO.setCreateTime(new Date());
                            groupRoleFunctionPO.setStatus(DataStatusEnum.NORMAL.getType());
                            roleFunctionPOList.add(groupRoleFunctionPO);
                        }
                        iOperateProjectDao.batchSaveRoleFunction(roleFunctionPOList);
                    }
                }catch (Exception e){
                    throw new DataAccessException("分配套餐物业菜单失败", e);
                }

            }
            //如项目变更场景，则需处理物业房屋的类型 社区场景为住宅1，非社区场景为办公3 社区场景Id固定为1070645309153116160
            if((StringUtils.isNotEmpty(oldProj.getSceneId()) && !oldProj.getSceneId().equals(updateDTO.getProjectSceneId())&& updateDTO.getProjectSceneId().equals("1070645309153116160"))||
                    (StringUtils.isEmpty(oldProj.getSceneId()) && updateDTO.getProjectSceneId().equals("1070645309153116160"))){
                iOperateProjectDao.updateRoomTypeByProjectId(updateDTO.getProjectId(),1);
            }
            if((StringUtils.isNotEmpty(oldProj.getSceneId()) && !oldProj.getSceneId().equals(updateDTO.getProjectSceneId())&& oldProj.getSceneId().equals("1070645309153116160"))||
                    (StringUtils.isEmpty(oldProj.getSceneId()) && !updateDTO.getProjectSceneId().equals("1070645309153116160"))){
                iOperateProjectDao.updateRoomTypeByProjectId(updateDTO.getProjectId(),3);
            }
        }

        if (projectPO.getIsPrivateCloud() == null || projectPO.getIsPrivateCloud() == 0 || oldProj.getIsPrivateCloud() == 0){
            //未启用私有云时使用默认云对讲业务服务器
            projectPO.setDeviceAddress(defaultBusinessServerUrl);
        }

        //1.启用云对讲时，项目需根据区域设置sip_id
        if (NumberHandlerUtil.isEqual(1, projectPO.getIsSmartCommunity())){
            projectPO.setSipId(iOperateProjectDao.getSipIdByDomain(projectPO.getCountryId(), projectPO.getProvinceId()));
        }
        projectPO.setCreateTime(null);//不允许更新创建时间
        projectPO.setUpdateTime(new Date());
        if(StringUtils.isNotBlank(updateDTO.getCloudServerCost())){
            projectPO.setCloudServiceCost(Integer.parseInt(updateDTO.getCloudServerCost()));
        }
        Map<String, Object> params = SqlUtil.durableData(projectPO, PlatformConstants.TABLE_UPDATE);

        if(StringUtils.isNotBlank(updateDTO.getOperateFunction()) && !updateDTO.getOperateFunction().contains("项目配置")){
            //如果修改项目时所关联的任务书编号不为空，则需变更项目与任务收间的关系 operate_project_assignment_info
            //先查询本项目下的任务书编号是否发生变化，若无则不进行处理，否则先删除再保存
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("projectId", projectPO.getProjectId());
            List<Map<String, Object>> batchParams = new ArrayList<>();
            String[] assignmentIdArr = StringHandlerUtil.splitString(updateDTO.getAssignmentIds());
            if (iOperateProjectDao.getProjectAssignmentInfo(paramsMap) > 0) {
                //先删除旧的项目与任务书间的关系
                iOperateProjectDao.updateProjectAssignmentInfo(paramsMap);
            }
            for (String assignmentId : assignmentIdArr) {
                OperateProjectAssignmentInfoPO assignmentInfoPO = new OperateProjectAssignmentInfoPO();
                assignmentInfoPO.setRelationId(LogicIdUtil.bussinessId());
                assignmentInfoPO.setAssignmentId(assignmentId);
                assignmentInfoPO.setProjectId(projectPO.getProjectId());
                assignmentInfoPO.setCreateTime(new Date());
                assignmentInfoPO.setUpdateTime(new Date());
                assignmentInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
                batchParams.add(SqlUtil.durableData(assignmentInfoPO, PlatformConstants.TABLE_SAVE));
            }
            if (batchParams.size() > 0) {
                iOperateProjectDao.batchSaveProjectAssignment(batchParams);
            }
        }

        //判断该项目是否绑定过人脸数据
        OperateSimpleFaceApplyInfoVO faceInfoVO = iOperateProjectDao.getProjectBingingFaceInfo(updateDTO.getProjectId());
        //启用人脸识别则更新人脸应用信息(人脸应用中项目绑定和识别率的设置)
        if((null!=updateDTO.getIsFaceRecognition())&&(updateDTO.getIsFaceRecognition()==1)){
            //如果项目之前绑定过人脸应用则清除原始记录(由于人脸库数据为空可以切换人脸库，需要清除上一次绑定的信息)
            if(faceInfoVO!=null){
                if((!updateDTO.getAppId().equals(faceInfoVO.getAppId()))){
                    //清除原始数据
                    iOperateProjectDao.updateFaceApplyInfo(null,faceInfoVO.getProjectId(),null,null,1);
                    iOperateProjectDao.updateFaceApplyInfo(updateDTO.getAppId(),updateDTO.getProjectId(),updateDTO.getFaceScore(),updateDTO.getFaceliveness(),1);
                }else{
                    iOperateProjectDao.updateFaceApplyInfo(updateDTO.getAppId(),updateDTO.getProjectId(),updateDTO.getFaceScore(),updateDTO.getFaceliveness(),1);
                }
            }else {
               // iOperateProjectDao.updateFaceApplyInfo(updateDTO.getAppId(), updateDTO.getProjectId(), updateDTO.getFaceScore(),updateDTO.getFaceliveness(), 1);
                //解决项目去掉人脸库的产生的bug
                FaceApplyInfoPO faceApplyInfoPO = new FaceApplyInfoPO();
                BeanUtils.copyProperties(updateDTO, faceApplyInfoPO);
                faceApplyInfoPO.setFace_score(faceApplyInfoPO.getFace_score()==null?"65":faceApplyInfoPO.getFace_score());

                faceApplyInfoPO.setAppId(appId);
                faceApplyInfoPO.setApiKey(apiKey);
                faceApplyInfoPO.setSecretKey(secretKey);
                faceApplyInfoPO.setApplyName("旺龙");
                faceApplyInfoPO.setCreateTime(new Date());
                Map map = SqlUtil.durableData(faceApplyInfoPO, PlatformConstants.TABLE_SAVE);
               iOperateProjectDao.save(map);
            }
        }else if((null!=updateDTO.getIsFaceRecognition())&&(updateDTO.getIsFaceRecognition()==0)){  //禁用人脸识别

            if(faceInfoVO!=null) {
                iOperateProjectDao.updateFaceApplyInfo(faceInfoVO.getAppId(), updateDTO.getProjectId(), faceInfoVO.getFaceScore(),faceInfoVO.getFaceliveness(), 2);
            }
        }
        if (NumberHandlerUtil.isEqual(1, projectPO.getIsSmartCommunity())){
            if (projectPO.getRootPort() == null){
                //rootPort未传时设为null
                Map<String, Object> port = new HashMap<>();
                port.put("columnName", "root_port");
                port.put("columnValue", null);
                ((ArrayList)params.get("list")).add(port);
            }
        }else {
            //未启用云对讲则不更新云对讲相关参数
            Iterator iterator = ((ArrayList)params.get("list")).iterator();
            while (iterator.hasNext()){
                Map map = (Map) iterator.next();
                String colName = map.get("columnName").toString();
                if ("out_code".equals(colName) ||
                        "root_pwd".equals(colName) ||
                        "root_port".equals(colName) ||
                        "watch_limit".equals(colName) ||
                        "talk_limit".equals(colName)){
                    iterator.remove();
                }
            }
        }

        Integer res = iOperateProjectDao.update(params);
        resultMap.put("result", res);
        resultMap.put("newProject", projectPO);
        resultMap.put("oldProject", oldProj);
        //补充newProject信息
        if(StringUtils.isBlank(projectPO.getProjectName())){
            projectPO.setProjectName(oldProj.getProjectName());
            projectPO.setCountryId(oldProj.getCountryId());
        }
        //当是否启用人脸识别变更时
        //当人脸识别启用时,之前未绑定过人脸库或当前AppId变更或人脸识别率变更或活体等级变更
        JSONObject dataJs = new JSONObject();
        JSONObject dataJsEntrance = new JSONObject();
        JSONObject json = new JSONObject();
        List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
        if (updateDTO.getIsFaceRecognition() != null && (!updateDTO.getIsFaceRecognition().equals(oldProj.getIsFaceRecognition())
                || ("1".equals(updateDTO.getIsFaceRecognition().toString()) && (faceInfoVO == null || !updateDTO.getAppId().equals(faceInfoVO.getAppId())
                || !updateDTO.getFaceScore().equals(faceInfoVO.getFaceScore()) || !updateDTO.getFaceliveness().equals(faceInfoVO.getFaceliveness()))))) {
            // 人脸库变更,新增,禁用操作推送消息到队列
            json.put("projectId", updateDTO.getProjectId());
            changeLogPOS.add(new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_FACE_INFO, json, updateDTO.getProjectId()));
            dataJs.put("data", changeLogPOS);
            List<DeviceBusinessEntranceChangeLogPO> entranceChangeLogPOS = new ArrayList<>();
            entranceChangeLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_FACE_INFO, json, projectPO.getProjectId()));
            dataJsEntrance.put("data", entranceChangeLogPOS);
        }
        //有人脸库变更数据则发送到消息队列中
        if (changeLogPOS.size() > 0) {
            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJsEntrance),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
        }

        //判断市级是否有修改,有则添加进入消息队列进行异地电话号处理
        if (oldProj.getCityId() == null || !oldProj.getCityId().equals(updateDTO.getCityId())) {
            Map<String, String> map = new HashMap<>();
            map.put("data", updateDTO.getProjectId());
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_PROJECT_UPDATE_PROJECT_ADDRESS_QUEUE,
                    JSON.toJSONString(map),
                    RabbitMQConstant.RABBITMQ_PROJECT_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_PROJECT_UPDATE_PROJECT_ADDRESS_ROUTING_KEY
            );
        }
        //当项目下是否配置人脸识别的状态由开启改为禁用时需向设备服务发送消息队列，将该项目下的所有设备的配置人脸识别的状态改为0
//        if (updateDTO.getIsFaceRecognition() != null && (updateDTO.getIsFaceRecognition()!=(oldProj.getIsFaceRecognition())&& updateDTO.getIsFaceRecognition()==0)) {
//            Map<String, String> statusMap = new HashMap<>();
//            statusMap.put("data", updateDTO.getProjectId());
//            messageSender.send(
//                    RabbitMQConstant.RABBITMQ_CLOUD_TALK_EQUIP_MODIFY_FACE_QUEUE,
//                    JSON.toJSONString(statusMap),
//                    RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
//                    RabbitMQConstant.RABBITMQ_CLOUD_TALK_EQUIP_MODIFY_FACE_KEY
//            );
//        }

        //记录操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateProjectDao.getUserInfo(updateDTO.getLoginUserId());
        OperationSpecialLogPO operationSpecialLogPO = handleSaveOperationLog(operateUserInfoPO);
        SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        operationSpecialLogPO.setIp(updateDTO.getIp());
        operationSpecialLogPO.setOuterId(projectPO.getProjectId());
        operationSpecialLogPO.setOperateFunction(updateDTO.getOperateFunction());
        operationSpecialLogPO.setOperateWay(updateDTO.getOperateWay());
        operationSpecialLogPO.setOperateData(JSON.toJSONString(updateDTO));

        if(updateDTO.getUpdateFlag()==null){
            operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + "于" + dateFormat.format(new Date()) + "作修改项目操作，" + "项目ID：" + projectPO.getProjectId() + "，项目名称：" + projectPO.getProjectName()+ "，项目状态：" + (1==updateDTO.getStatus() ? "启用" : "禁用"));
        } else if(updateDTO.getUpdateFlag()!=null && updateDTO.getUpdateFlag().equals(1)){
            operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + "于" + dateFormat.format(new Date()) + "作项目配置操作，" + "项目ID：" + projectPO.getProjectId() + "，项目名称：" + projectPO.getProjectName());
        }else {
            operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + "于" + dateFormat.format(new Date()) + "作修改项目操作，" + "项目ID：" + projectPO.getProjectId() + "，项目名称：" + projectPO.getProjectName() + "，项目属性：" + (0==projectPO.getProjectProperty() ? "正式项目" : "非正式项目"));
        }

        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(new Date());
        operationSpecialLogPO.setUpdateTime(new Date());
        res = iOperateProjectDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));

        //保存证书信息  ProjectSystem：2线下平台线下平台保存证书
        if (updateDTO.getUpdateFlag()!=null && updateDTO.getUpdateFlag().equals(1) && updateDTO.getProjectSystem().contains("2")){
            res = saveLicenseInfo(updateDTO, projectPO);
        }
        //同步ProjectInfo到线下平台
        boolean resultProjectInfo = pushProjectInfoToOffline(UPDATE_OPERATION, new Date(), projectPO);

        if (!(resultProjectInfo && res > 0)) {
            if (updateDTO.getUpdateFlag().equals(0)){
                throw new DataAccessException("【编辑项目失败】");
            }else {
                throw new DataAccessException("【配置项目失败】");
            }
        }
        return resultMap;
    }

    /**
     * <desc>
     *      场景变更，物业项目用户类型相关逻辑变更
     * <desc/>
     *
     * @param updateDTO 项目更新信息
     * @param oldProj 数据库项目信息
     * @return
     * @author Juguang.S
     * @createDate 2021/04/19
     */
    private Integer propertyProjectUserTypeData(OperateProjectUpdateDTO updateDTO,ProjectPO oldProj) throws Exception{
        if(updateDTO.getUpdateFlag()!=null && updateDTO.getUpdateFlag()==1){
            Integer count = iOperateProjectDao.getPropertyUserType(updateDTO.getProjectId());
            int maxCount=0;
            boolean mark = false;
            List<Map<String, Object>> saveList = new ArrayList<>();
            Date date = new Date();
            if(StringUtils.isNotBlank(oldProj.getSceneId()) && oldProj.getSceneId().equals(updateDTO.getProjectSceneId())){
                return 1;
            }
            if(StringUtils.isNotBlank(oldProj.getSceneId()) && !oldProj.getSceneId().equals(updateDTO.getProjectSceneId()) && count == 0){
                iOperateProjectDao.deletePropertyUserTypeByProjectId(updateDTO.getProjectId());
            }
            //此处处理变更项目场景配置后，物业项目用户类型也需变动，如物业用户类型已被关联过，则即使切换场景也不变更物业用户类型，若首次选择场景，则需初始化物业用户类型
            if(StringUtils.isBlank(oldProj.getSceneId()) || count==0){
                List<Map<String,Object>> userTypeList = iOperateProjectDao.getUserTypeBySceneId(updateDTO.getProjectSceneId());
                if(userTypeList!=null){
                    maxCount = 1;
                    for(Map<String,Object> map : userTypeList){
                        PropertyProjectUserTypeInfoPO projectUserTypeInfoPO = new PropertyProjectUserTypeInfoPO();
                        projectUserTypeInfoPO.setUserTypeId(LogicIdUtil.bussinessId());
                        projectUserTypeInfoPO.setUserTypeName(map.get("name").toString());
                        if("1".equals(map.get("special").toString())){
                            mark = true;
                        }
                        projectUserTypeInfoPO.setProjectId(updateDTO.getProjectId());
                        if(maxCount==3){
                            maxCount=4;
                        }
                        projectUserTypeInfoPO.setSpecialType(maxCount+1);
                        projectUserTypeInfoPO.setCreateTime(date);
                        projectUserTypeInfoPO.setUpdateTime(date);
                        maxCount++;
                        saveList.add(SqlUtil.durableData(projectUserTypeInfoPO, PlatformConstants.TABLE_SAVE));
                    }
                    if(mark){
                        maxCount=1;
                        //单独处理社区场景类型
                        saveList = new ArrayList<>();
                        PropertyProjectUserTypeInfoPO userTypeInfoPO1 = new PropertyProjectUserTypeInfoPO();
                        userTypeInfoPO1.setProjectId(updateDTO.getProjectId());
                        userTypeInfoPO1.setUserTypeId(LogicIdUtil.bussinessId());
                        userTypeInfoPO1.setSpecialType(1);
                        userTypeInfoPO1.setIsDelete(0);
                        userTypeInfoPO1.setUserTypeName("户主");
                        userTypeInfoPO1.setCreateTime(date);
                        userTypeInfoPO1.setUpdateTime(date);
                        saveList.add(SqlUtil.durableData(userTypeInfoPO1, PlatformConstants.TABLE_SAVE));
                        for(int i=1;i<userTypeList.size(); i++){
                            PropertyProjectUserTypeInfoPO userTypeInfoPO2 = new PropertyProjectUserTypeInfoPO();
                            userTypeInfoPO2.setProjectId(updateDTO.getProjectId());
                            userTypeInfoPO2.setUserTypeId(LogicIdUtil.bussinessId());
                            if(maxCount==3){
                                maxCount=4;
                            }
                            userTypeInfoPO2.setSpecialType(maxCount+1);
                            userTypeInfoPO2.setIsDelete(1);
                            userTypeInfoPO2.setUserTypeName(userTypeList.get(i).get("name").toString());
                            userTypeInfoPO2.setCreateTime(date);
                            userTypeInfoPO2.setUpdateTime(date);
                            maxCount++;
                            saveList.add(SqlUtil.durableData(userTypeInfoPO2, PlatformConstants.TABLE_SAVE));
                        }
                    }
                    if(saveList!=null){
                        iOperateProjectDao.batchSaveByUserType(saveList);
                    }
                }
            }
        }
        return 1;
    }

    /**
     * <desc>
     *      更保存证书信息
     * <desc/>
     *
     * @param updateDTO 项目更新信息
     * @param projectPO 项目信息
     * @return
     * @author caoshuai
     * @createDate 2020/10/10
     */
    private Integer saveLicenseInfo(OperateProjectUpdateDTO updateDTO, ProjectPO projectPO) throws Exception {

        ProjectPO projectInfoPo= iOperateProjectDao.getProjectInfoById(projectPO.getProjectId());
        //项目信息
        Map<Object, Object> projectInfo = new HashMap<>(16);
        projectInfo.put("projectId", projectInfoPo.getProjectId());
        projectInfo.put("projectName", projectInfoPo.getProjectName());
        projectInfo.put("customerName", projectInfoPo.getCustomerName());
        projectInfo.put("projectFile", projectInfoPo.getProjectFile());
        projectInfo.put("projectRemark", projectInfoPo.getProjectMemo());

        //证书信息
        Map<Object, Object> licenseInfo = new HashMap<>(16);
        licenseInfo.put("version", licenseVersion);
        Integer MaxLicenseNo = iOperateProjectDao.getLicenseNoByProjectId(projectPO.getProjectId());
        licenseInfo.put("licenseNo", MaxLicenseNo + 1);
        licenseInfo.put("qrkeyvalue", projectInfoPo.getPubKey());

        //产品属性
        Map<Object, Object> productConfig = new HashMap<>(16);
        productConfig.put("productType", projectInfoPo.getProductType());
        productConfig.put("productAttribute", updateDTO.getProductAttribute());
        productConfig.put("configRemark", projectInfoPo.getProjectMemo());
        String[] credentialInfoArr = updateDTO.getCredentialInfo().split(",");
        //计算授权凭证
        Integer credential = SmartCardAuthEvidenceTypeEnum.getByType(Integer.valueOf(credentialInfoArr[0])).getCode();
        for (int i = 1; i < credentialInfoArr.length; i++) {
            int credential1 = SmartCardAuthEvidenceTypeEnum.getByType(Integer.valueOf(credentialInfoArr[i])).getCode();
            credential = credential | credential1;

        }
//        for(String credentialInfoFlag: credentialInfoArr){
//            String s = Integer.toBinaryString(SmartCardAuthEvidenceTypeEnum.getByType(Integer.valueOf(credentialInfoFlag)).getCode());
//
//        }
        productConfig.put("credentialInfo", credential);

        Map<Object, Object> licenseContentInfo = new HashMap<>(16);
        licenseContentInfo.put("licenseInfo", licenseInfo);
        licenseContentInfo.put("projectInfo", projectInfo);
        licenseContentInfo.put("bindServerPC", new ArrayList<>());
        licenseContentInfo.put("systemAuth", updateDTO.getSystemAuth());
        licenseContentInfo.put("productConfig", productConfig);


        ProjectLicensePO projectLicensePO = new ProjectLicensePO();
        projectLicensePO.setLicenseId(idWorker.nextId() + "");
        projectLicensePO.setProjectId(projectPO.getProjectId());
        projectLicensePO.setLicenseInfo(JSONObject.toJSONString(licenseContentInfo));
        projectLicensePO.setLicenseNo(MaxLicenseNo + 1);
        projectLicensePO.setLicenseVersion(licenseVersion);
        projectLicensePO.setCreateTime(new Date());
        projectLicensePO.setStatus(1);
        Integer res = iOperateProjectDao.save(SqlUtil.durableData(projectLicensePO, PlatformConstants.TABLE_SAVE));
        return res;
    }

    /**
     * <desc>
     *      根据项目信息变化发送相应消息通知
     * <desc/>
     *
     * @param projectPO 最新项目信息
     * @param oldProj 旧项目信息
     * @return
     * @author Chunjian.G
     * @createDate 2018-02-25
     */
    private void sendProjectChangedMessage(ProjectPO projectPO, ProjectPO oldProj) throws Exception{
        /*1.通知云对讲重启：
         * a.云对讲启用状态更改
         * b.云对讲业务服务器地址更改
         * c.项目状态更改 启用->禁用（禁用->启用无需重启）
         */
        if ((projectPO.getIsSmartCommunity() != null && !projectPO.getIsSmartCommunity().equals(oldProj.getIsSmartCommunity()))
                ||(StringUtils.isNotBlank(projectPO.getDeviceAddress()) && !projectPO.getDeviceAddress().equals(oldProj.getDeviceAddress()))
                ||(projectPO.getStatus() != null && !projectPO.getStatus().equals(oldProj.getStatus()) && projectPO.getStatus() == 2)){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", projectPO.getProjectId());
            List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
            changeLogPOS.add(new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_RELOGIN, jsonObject, projectPO.getProjectId()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeLogPOS);

            //发送云对讲指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY
            );
            System.out.println(String.format("【%s】通知云对讲重启：projectId-%s，deviceAddress-%s",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), projectPO.getDeviceAddress()));

        }

        //开门密码状态变更
        if(projectPO.getOpenPwd()!=null && !projectPO.getOpenPwd().equals(oldProj.getOpenPwd())){
            //推送云对讲指令
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", projectPO.getProjectId());
            List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
            changeLogPOS.add(new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_FULL, jsonObject, projectPO.getProjectId()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeLogPOS);
            //发送云对讲指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY
            );

            //云门禁
            JSONObject entranceJson = new JSONObject();
            entranceJson.put("projectId", projectPO.getProjectId());
            List<DeviceBusinessEntranceChangeLogPO> entranceChangeLogPOS = new ArrayList<>();
            entranceChangeLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_RE_LOGIN, entranceJson, projectPO.getProjectId()));
            dataJs.put("data", entranceChangeLogPOS);
            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );

            //云电梯
            List<DeviceBusinessElevatorChangeLogPO> deviceElevatorChangeLogPOS = new ArrayList<>();
            deviceElevatorChangeLogPOS.add(new DeviceBusinessElevatorChangeLogPO(projectPO.getProjectId(),
                    CloudElevatorChangeBusinessEnum.PUSH_ROOM_FULL,jsonObject.toJSONString()));
            dataJs.put("data",deviceElevatorChangeLogPOS);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
        }

        if ((StringUtils.isNotBlank(projectPO.getDeviceAddress()) && !projectPO.getDeviceAddress().equals(oldProj.getDeviceAddress()))
                ||(projectPO.getStatus() != null && !projectPO.getStatus().equals(oldProj.getStatus()) && projectPO.getStatus() == 2)){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", projectPO.getProjectId());
            List<DeviceBusinessEntranceChangeLogPO> changeLogPOS = new ArrayList<>();
            changeLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_RE_LOGIN, jsonObject, projectPO.getProjectId()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeLogPOS);

            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
            System.out.println(String.format("【%s】通知云门禁重启：projectId-%s，deviceAddress-%s",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), projectPO.getDeviceAddress()));

        }

        if((StringUtils.isNotBlank(projectPO.getDeviceAddress()) && !projectPO.getDeviceAddress().equals(oldProj.getDeviceAddress()))
                ||(projectPO.getStatus() != null && !projectPO.getStatus().equals(oldProj.getStatus()) && projectPO.getStatus() == 2)){

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", projectPO.getProjectId());
            List<DeviceBusinessElevatorChangeLogPO> elevatorLogs = new ArrayList<>();
            elevatorLogs.add(new DeviceBusinessElevatorChangeLogPO(projectPO.getProjectId(), CloudElevatorChangeBusinessEnum.PUSH_SERVER, jsonObject.toJSONString()));
            JSONObject dataJs = new JSONObject();
            //发送云电梯指令
            dataJs.put("data",elevatorLogs);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
            System.out.println(String.format("【%s】通知云电梯重启：projectId-%s，deviceAddress-%s",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), projectPO.getDeviceAddress()));
        }


        if (isProjectInfoChanged(projectPO, oldProj,1)){
            //项目信息关键变更需通知云对讲
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId",projectPO.getProjectId());
            List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
            changeLogPOS.add(new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_PROJECT, jsonObject, projectPO.getProjectId()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeLogPOS);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY
            );
            System.out.println(String.format("【%s】通知项目信息变更：projectId-%s",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId()));
        }
        if (isProjectInfoChanged(projectPO,oldProj,2)){
            //项目信息变更通知云电梯
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId",projectPO.getProjectId());
            List<DeviceBusinessElevatorChangeLogPO> changeLogPOs = new ArrayList<>();
            changeLogPOs.add(new DeviceBusinessElevatorChangeLogPO(projectPO.getProjectId(),CloudElevatorChangeBusinessEnum.PUSH_PROJECT,jsonObject.toJSONString()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data",changeLogPOs);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
        }

        if (isProjectInfoChanged(projectPO,oldProj,2)){
            //项目信息变更通知云门禁
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", projectPO.getProjectId());
            List<DeviceBusinessEntranceChangeLogPO> changeLogPOS = new ArrayList<>();
            changeLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_PROJECT, jsonObject, projectPO.getProjectId()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeLogPOS);

            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
        }

        //判断是否切换了iot对接方
        //判断云电梯是否切换,群控器是否切换
        if(projectPO.getIotFlag() != null && projectPO.getIotFlag() != oldProj.getIotFlag()) {
            redisService.del(RedisConstant.PROJECT_IOT_TYPE_REDIS_KEY+projectPO.getProjectId());
//            iOperateProjectDao.updateElevatorIotProduct(projectPO.getProjectId(), projectPO.getIotFlag());
//            iOperateProjectDao.updateControllerIotProduct(projectPO.getProjectId(), projectPO.getIotFlag());
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", projectPO.getProjectId());
            jsonObject.put("iotFlag",oldProj.getIotFlag());
            List<DeviceBusinessElevatorChangeLogPO> elevatorLogs = new ArrayList<>();
            elevatorLogs.add(new DeviceBusinessElevatorChangeLogPO(projectPO.getProjectId(), CloudElevatorChangeBusinessEnum.PUSH_SERVER, jsonObject.toJSONString()));
            JSONObject dataJs = new JSONObject();
            //发送云电梯指令
            dataJs.put("data", elevatorLogs);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);


            //处理门禁相关
            JSONObject entranceJson = new JSONObject();
            entranceJson.put("projectId", projectPO.getProjectId());
            entranceJson.put("iotFlag",oldProj.getIotFlag());
            List<DeviceBusinessEntranceChangeLogPO> entranceChangeLogPOS = new ArrayList<>();
            entranceChangeLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_RE_LOGIN, entranceJson, projectPO.getProjectId()));
            JSONObject dataJs2 = new JSONObject();
            dataJs2.put("data", entranceChangeLogPOS);
            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJs2),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
            //清除设备在线缓存
            Set<String> resultElevator = redisService.getKeys(RedisConstant.DEVICE_ELEVATOR_IS_ONLINE_KEY + projectPO.getProjectId() + "*") == null ? new HashSet<>() : redisService.getKeys(RedisConstant.DEVICE_ELEVATOR_IS_ONLINE_KEY + "*");//云电梯在线设备
            Set<String> resultEntrance = redisService.getKeys(RedisConstant.DEVICE_ENTRANCE_IS_ONLINE_KEY + projectPO.getProjectId() + "*") == null ? new HashSet<>() : redisService.getKeys(RedisConstant.DEVICE_ENTRANCE_IS_ONLINE_KEY + "*");//云门禁在线设备
            Set<String> resultCluster = redisService.getKeys(RedisConstant.DEVICE_CLUSTER_IS_ONLINE_KEY + projectPO.getProjectId() + "*") == null ? new HashSet<>() : redisService.getKeys(RedisConstant.DEVICE_CLUSTER_IS_ONLINE_KEY + "*");//云群控器在线设备
            Set<String> resultWippen = redisService.getKeys(RedisConstant.DEVICE_WIPPEN_IS_ONLINE_KEY + projectPO.getProjectId() + "*") == null ? new HashSet<>() : redisService.getKeys(RedisConstant.DEVICE_WIPPEN_IS_ONLINE_KEY + "*");//云联动器在线设备
            for (String deviceKey : resultElevator) {//电梯
                redisService.del(deviceKey);
            }
            for (String deviceKey : resultEntrance) {//门禁
                redisService.del(deviceKey);
            }
            for (String deviceKey : resultCluster) {//群控器
                redisService.del(deviceKey);
            }
            for (String deviceKey : resultWippen) {//联动器
                redisService.del(deviceKey);
            }
        }

        //2.通知用户服务项目启用/禁用云对讲
        if (projectPO.getIsSmartCommunity() != null && !projectPO.getIsSmartCommunity().equals(oldProj.getIsSmartCommunity())){
            ProjectSmartCommunityStatusChangeDTO changeDTO = new ProjectSmartCommunityStatusChangeDTO();
            changeDTO.setProjectId(projectPO.getProjectId());
            changeDTO.setIsSmartCommunity(projectPO.getIsSmartCommunity());
            JSONObject dataJs = new JSONObject();
            dataJs.put("data", changeDTO);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_PROJECT_SMART_COMMUNITY_STATUS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_USER_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_PROJECT_SMART_COMMUNITY_STATUS_KEY
            );


            //如果云对讲禁用后转启用，通知物业同步设备Sip数据
            if(ProjectSmartCommunityStatusEnum.PROJECT_SMART_COMMUNITY_YES.getType().equals(projectPO.getIsSmartCommunity())){

                JSONObject datajs = new JSONObject();
                datajs.put("data",projectPO.getProjectId());
                messageSender.send(
                        RabbitMQConstant.RABBITMQ_SYNC_EQUIP_SIP_WHEN_ENABLE_CLOUD_QUEUE,
                        JSON.toJSONString(datajs),
                        RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
                        RabbitMQConstant.RABBITMQ_SYNC_EQUIP_SIP_WHEN_ENABLE_CLOUD_KEY
                );
            }
            System.out.println(String.format("【%s】通知用户服务项目云对讲启用状态：projectId-%s，isSmartCommunity-%d",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), projectPO.getIsSmartCommunity()));
        }
        //3.通知项目状态启用/禁用
        if (projectPO.getStatus() != null && !projectPO.getStatus().equals(oldProj.getStatus())){
            //a.通知更新app用户设备列表缓存
            Map<String, String> map = new HashMap<>();
            map.put("projectId", projectPO.getProjectId());
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_QUEUE,
                    JSON.toJSONString(map),
                    RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_KEY
            );
            //b.通知更新app用户二维码
//            messageSender.send(
//                    RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_QRCODE_UPDATE_QUEUE,
//                    JSON.toJSONString(map),
//                    RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
//                    RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_QRCODE_UPDATE_KEY
//            );
            //c.通知APP项目状态变更
            JSONObject dataJsApp = new JSONObject();
            dataJsApp.put("data", projectPO);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_PROJECT_STATUS_QUEUE,
                    JSON.toJSONString(dataJsApp),
                    RabbitMQConstant.RABBITMQ_HOUSEHOLD_JPUSH_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_PROJECT_STATUS_KEY
            );
            System.out.println(String.format("【%s】通知项目状态变更：projectId-%s，status-%d",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), projectPO.getStatus()));

            //d.禁用物业账号消息通知
            if (NumberHandlerUtil.isEqual(projectPO.getStatus(), DataStatusEnum.BAN.getType())){
                List<String> propUserIds = iOperateProjectDao.getPropertyUserIdsByProjectId(projectPO.getProjectId());
                List<String> userIdList = new ArrayList<>();
                if(propUserIds != null && !propUserIds.isEmpty()){
                    for(String userId : propUserIds){
                        if(iOperateProjectDao.getProjectUserInfo(userId)==0){
                            userIdList.add(userId);
                        }
                    }
                }

                if (null != userIdList && !userIdList.isEmpty()){
                    for (int i = 0; i< userIdList.size(); i++){
                        propUserIds.set(i, String.format("%s%s", RedisConstant.PROPERTY_USER_REDIS_KEY, userIdList.get(i)));
                    }
                    JSONObject dataJs = new JSONObject();
                    dataJs.put("data", propUserIds);
                    messageSender.send(RabbitMQConstant.RABBITMQ_DELETE_CACHE_QUEUE, JSON.toJSONString(dataJs),
                            RabbitMQConstant.RABBITMQ_USER_EXCHANGE, RabbitMQConstant.RABBITMQ_DELETE_CACHE_KEY);
                    System.out.println(String.format("【%s】通知删除项目关联物业账号缓存：projectId-%s，userIds-%s",
                            DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), JSON.toJSONString(dataJs)));
                }
            }
        }
        //4.通知项目蓝牙电梯启用/禁用
        if (projectPO.getIsBluetoothElevator() != null && !projectPO.getIsBluetoothElevator().equals(oldProj.getIsBluetoothElevator())){
            JSONObject dataJsApp = new JSONObject();
            dataJsApp.put("data", projectPO);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_PROJECT_BLUETOOTH_ELEVATOR_QUEUE,
                    JSON.toJSONString(dataJsApp),
                    RabbitMQConstant.RABBITMQ_HOUSEHOLD_JPUSH_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_PROJECT_BLUETOOTH_ELEVATOR_KEY
            );
            System.out.println(String.format("【%s】通知项目蓝牙电梯状态变更：projectId-%s，isBluetoothElevator-%d",
                    DateUtil.fomatDate1(new Date()), projectPO.getProjectId(), projectPO.getIsBluetoothElevator()));
        }
        //5.无接触二维码开关,通知app重新拉取
        if (projectPO.getNotouchFlag() != null && !projectPO.getNotouchFlag().equals(oldProj.getNotouchFlag())){
            //c.通知APP项目状态变更
            JSONObject dataJsApp = new JSONObject();
            dataJsApp.put("data", projectPO);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_PROJECT_STATUS_QUEUE,
                    JSON.toJSONString(dataJsApp),
                    RabbitMQConstant.RABBITMQ_HOUSEHOLD_JPUSH_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_PROJECT_STATUS_KEY
            );
        }
        //项目禁用，清空该项目下的物业app用户登录缓存
        if (2 == projectPO.getStatus()) {
            List<String> cacheKeyList = new ArrayList<>();
            List<String> userIdList = iOperateProjectDao.getProjectUsers(oldProj.getProjectId());
            if (userIdList != null && !userIdList.isEmpty()) {
                for (String userId : userIdList) {
                    cacheKeyList.add(String.format("%s%s", RedisConstant.PROPERTY_APP_REDIS_USER_KEY, userId));
                }
            }
            if (!cacheKeyList.isEmpty()) {
                JSONObject datajs = new JSONObject();
                datajs.put("data", cacheKeyList);
                messageSender.send(RabbitMQConstant.RABBITMQ_DELETE_CACHE_QUEUE, JsonUtil.toJSON(datajs),
                        RabbitMQConstant.RABBITMQ_USER_EXCHANGE, RabbitMQConstant.RABBITMQ_DELETE_CACHE_KEY);
            }
        }
    }

    /**
     * <desc>
     *      判断项目变更信息类别
     * </desc>
     *
     * @param newProj 变更信息
     * @param oldProj 旧信息
     * @param type 设备类型 1云对讲 2云电梯
     * @return
     * @author Jiaqi.X
     * @createDate 2018/04/08
     */
    private boolean isProjectInfoChanged(ProjectPO newProj, ProjectPO oldProj,Integer type){
        if(type == 1) {
             /*项目关键信息是否变更
            * 小区名称，工程密码，物业联系方式，出局码，root密码，root端口，监视时长，对讲时长，PSTN开关
            * */
            if ((newProj.getProjectName() != null && !newProj.getProjectName().equals(oldProj.getProjectName())
                    || (newProj.getEngineerCode() != null && !newProj.getEngineerCode().equals(oldProj.getEngineerCode())))
                    || (newProj.getManagePhone() != null && !newProj.getManagePhone().equals(oldProj.getManagePhone()))
                    || (newProj.getOutCode() != null && !newProj.getOutCode().equals(oldProj.getOutCode()))
                    || (newProj.getRootPwd() != null && !newProj.getRootPwd().equals(oldProj.getRootPwd()))
                    || (newProj.getRootPort() != null && !newProj.getRootPort().equals(oldProj.getRootPort()))
                    || (newProj.getWatchLimit() != null && !newProj.getWatchLimit().equals(oldProj.getWatchLimit()))
                    || (newProj.getTalkLimit() != null && !newProj.getTalkLimit().equals(oldProj.getTalkLimit()))
                    || (newProj.getOnOffLinePadFace()!= null && !newProj.getOnOffLinePadFace().equals(oldProj.getOnOffLinePadFace()))
                    || (newProj.getPsntOpen()!= null && !newProj.getPsntOpen().equals(oldProj.getPsntOpen()))
                    || (newProj.getChargeMode() != null && !newProj.getChargeMode().equals(oldProj.getChargeMode()))) {
                return true;
            }
        }else if(type == 2){
            /*项目关键信息是否变更
            * 小区名称，root密码，root端口,项目是否启用云电梯
            * */
            if (newProj.getProjectName() != null && !newProj.getProjectName().equals(oldProj.getProjectName())
                    || (newProj.getRootPwd() != null && !newProj.getRootPwd().equals(oldProj.getRootPwd()))
                    || (newProj.getRootPort() != null && !newProj.getRootPort().equals(oldProj.getRootPort()))
                    || (newProj.getIsCloudElevator() != null && !newProj.getIsCloudElevator().equals(oldProj.getIsCloudElevator()))
                    || (newProj.getChargeMode() != null && !newProj.getChargeMode().equals(oldProj.getChargeMode()))) {
                return true;
            }
        }
        return false;
    }

    /**
     * <desc>
     * 更新单个项目信息
     * <desc/>
     *
     * @param updateDTO 项目更新信息
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-11
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer updateProject(OperateProjectUpdateDTO updateDTO) throws Exception {
        //1.更新项目信息
        Map<String, Object> resultMap = this.updateProjectTrans(updateDTO);
        if(resultMap!=null){
            //2.发送消息通知
            this.sendProjectChangedMessage((ProjectPO) resultMap.get("newProject"), (ProjectPO) resultMap.get("oldProject"));
            return (Integer) resultMap.get("result");
        }
        return 1;
    }

    /**
     * <desc>
     * 分页查询项目信息
     * <desc/>
     *
     * @param pageDTO 分页查询项目信息DTO
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-10
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<OperateProjectVO> getPage(OperateProjectGetPageDTO pageDTO) throws Exception {
        if(StringUtils.isBlank(pageDTO.getOrderColumn())){
            pageDTO.setOrderColumn("createTime");
            pageDTO.setOrderRule("DESC");
        }
        //分页对象
        Page<OperateProjectVO> page = new Page<>();
        //将DTO转换为Map
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(pageDTO, page);
        String[] sceneIdArr = StringHandlerUtil.splitString(pageDTO.getProjectSceneId());
        params.put("sceneIdArr",sceneIdArr);
        List<String> cloudStatus = StringHandlerUtil.splitStringList(pageDTO.getCloudStatus());
        List<String> smartCardStatus = StringHandlerUtil.splitStringList(pageDTO.getSmartCardStatus());
        List<String> projectProperty = StringHandlerUtil.splitStringList(pageDTO.getProjectProperty());
        if (cloudStatus.size() > 1){
            params.remove("cloudStatus");
        }
        if (smartCardStatus.size() > 1){
            params.remove("smartCardStatus");
        }
        params.put("projectProperty", projectProperty);
        //查询
        List<OperateProjectVO> projectVOS = iOperateProjectDao.getSimplePage(params);
        Integer count = iOperateProjectDao.getCount(params);
        //填充返回数据集
        page.setRows(projectVOS, count);
        return page;
    }

    /**
     * <desc>
     * 获取单个项目详情
     * <desc/>
     *
     * @param projectId 项目编号
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-11
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public OperateProjectDetailVO getDetail(String projectId) throws Exception {
        OperateProjectDetailVO detailVO = iOperateProjectDao.getDetail(projectId);
        //根据项目编号查询套餐ID
        Map<String,Object> resultMap = iOperateProjectDao.getPackageId(projectId);
        if(resultMap!=null){
            detailVO.setProjectPackageId(StringHandlerUtil.getNullOrStringForObject(resultMap.get("projectPackageId")));
            detailVO.setPackageName(StringHandlerUtil.getNullOrStringForObject(resultMap.get("packageName")));
        }
        //查询项目下所关联的任务书相关信息
        detailVO.setAssignmentDataVOList(iOperateProjectDao.getProjectAssignmentInfoList(projectId));
        SimpleDateFormat dateFormat1 = new SimpleDateFormat(DateUtil.YMDSQL);
        SimpleDateFormat dateFormat2 = new SimpleDateFormat(DateUtil.YYYYMMDD);
        //获取关联的设备列表
        if (detailVO != null){
            Map<String, Object> params = new HashMap<>();
            Integer maxLicenseNo = iOperateProjectDao.getMaxLicenseNo(projectId);
            params.put("projectId", projectId);
            params.put("licenseNo", maxLicenseNo);
            detailVO.setRelatedProducts(iOperateProjectDao.getRelatedProducts(projectId));
            detailVO.setFaceApplyInfo(iOperateProjectDao.getProjectBingingFaceInfo(projectId));
            detailVO.setLicenseInfo(iOperateProjectDao.getAllLicenseDetailVO(params));
            ProjectLicensePO projectLicensePO = iOperateProjectDao.getLicense(projectId);
            if (projectLicensePO != null){
                //从licenseInfo中解析相关配置信息
                String licenseInfo = projectLicensePO.getLicenseInfo();
                if (licenseInfo != null){
                    JSONObject jsonObject = JSONObject.parseObject(licenseInfo);
                    JSONArray operateSystemAuthInfoVO = jsonObject.getJSONArray("systemAuth");
                    List<OperateSystemAuthInfoVO> systemAuthInfoVOS = JSONArray.parseArray(JSONObject.toJSONString(operateSystemAuthInfoVO), OperateSystemAuthInfoVO.class);

                    //证书中的时间格式是yyyyMMdd格式，需要转换为yyyy-MM-dd
                    for (OperateSystemAuthInfoVO authInfoVO : systemAuthInfoVOS){

                        //线下平台证书中FFFFFFFF为长期有效
                        if (authInfoVO.getEndDate() != null && !authInfoVO.getEndDate().equals("FFFFFFFF") && !authInfoVO.getEndDate().contains("-")){
                            authInfoVO.setEndDate(dateFormat1.format(dateFormat2.parse(authInfoVO.getEndDate())));
                        }
                    }

                    detailVO.setSystemAuth(systemAuthInfoVOS);
                    JSONObject productConfig = jsonObject.getJSONObject("productConfig");
                    int productAttribute = Integer.parseInt(productConfig.get("productAttribute").toString());
                    detailVO.setProductAttribute(productAttribute);
                    if(!productConfig.containsKey("credentialInfo")){
                        return detailVO;
                    }
                    int credentialInfo = productConfig.getInteger("credentialInfo");

                    //根据授权凭证解析出授权信息
                    StringBuilder authStr = new StringBuilder();
                    //权限值和权限类型Code做按位与操作
                    for (int i = 1; i < SmartCardAuthEvidenceTypeEnum.values().length - 1; i++){
                        //分别和各个type做按位与操作
                        if((credentialInfo & SmartCardAuthEvidenceTypeEnum.getByType(i).getCode()) >0){
                            authStr.append(SmartCardAuthEvidenceTypeEnum.getByType(i).getType());
                            authStr.append(",");
                        }
                    }
                    //去除字符串末尾的逗号并存到授权凭证字段中
                    detailVO.setCredentialInfo( authStr.substring(0, authStr.length()-1));
                    StringHandlerUtil.formatString(detailVO);
                }
            }
        }
        return detailVO;
    }


    /**
     * <desc>
     * 单表-获取项目信息
     * <desc/>
     *
     * @param projectId 项目编号
     * @return
     * @author Chunjian.G
     * @createDate 2017-12-05
     */
    @Override
    public ProjectPO getOneProject(String projectId) throws Exception {
        return iOperateProjectDao.getOne(projectId);
    }

    /**
     * <desc>
     * 查询单个项目的关联设备列表
     * <desc/>
     *
     * @param projectId 项目编号
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<OperateProjectRelatedProductVO> getRelatedProducts(String projectId) throws Exception {
        List<OperateProjectRelatedProductVO> products = iOperateProjectDao.getRelatedProducts(projectId);
        return products;
    }

    /**
     * <desc>
     * 保存单个项目的关联设备（会先删除之前的关联记录）
     * <desc/>
     *
     * @param projectId 项目ID
     * @param saveDTOS   关联设备新增信息
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer saveRelatedProducts(String projectId, List<OperateProjectRelatedProductSaveDTO> saveDTOS) throws Exception {
        //先删除该项目之前的设备关联记录
        Integer res = iOperateProjectDao.removeRelatedProducts(projectId);
        //保存新的关联记录
        if (saveDTOS != null && saveDTOS.size() > 0){
            res = iOperateProjectDao.saveRelatedProducts(projectId, saveDTOS);
        }
        return res;
    }

    /**
     * <desc>
     *      根据用户id查询关联的所有项目id及名称
     * </desc>
     *
     * @param userId 用户id
     * @return
     * @aurhor Jiaqi.X
     * @createDate 2017/10/11
     */
    @Override
    public Map<String,Object> getEngineerProjectInfo(@Param("userId")String userId){
        return iOperateProjectDao.getEngineerProjectInfo(userId);
    }

    /**
     * <desc>
     *      获取所有项目信息，只取id及名称供下拉菜单使用
     * </desc>
     *
     * @return
     * @author Jiaqi.X
     * @craeteDate 2017/10/11
     */
    @Override
    public Page<OperateAllotProjectVO> getAllotProjectPage(OperateAllotProjectDTO pageDTO) throws Exception {
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(pageDTO);
        //分页类默认pageSize为20
        Page<OperateAllotProjectVO> page = new Page<>();
        page.getPage().setPageSize(pageDTO.getPageSize());
        page.getPage().setCurrentPage(pageDTO.getCurrentPage());
        params.put("currentPage",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        page.setRows(iOperateProjectDao.getAllotProjectPage(params), iOperateProjectDao.getAllotProjectPageCount(params));
        return page;
    }


    /**
     * <desc>
     *      更改项目状态
     * <desc/>
     *
     * @param projectId 项目Id
     * @param status 项目状态，默认1，0-删除，1启用，2-禁用
     * @return
     * @author zhangs
     * @createDate 2017/10/31
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateProjectStatus(String projectId, String status) throws Exception{
        if(StringUtils.isBlank(projectId) || StringUtils.isBlank(status)) {
            return;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("projectId", projectId);
        params.put("status", status);
        iOperateProjectDao.updateProjectStatus(params);
    }

    /**
     * <desc>
     *      是否启用云对讲。
     * <desc/>
     *
     * @param  projectId 项目编号
     * @return 0-禁用  1-启用
     * @author shengen.T
     * @createDate 2017-11-30
     */
    @Override
    public Integer getIsSmartCommunity(String projectId) throws Exception{
         return iOperateProjectDao.getIsSmartCommunity(projectId);
    }

    /**
     * <desc>
     *      是否启用云电梯和蓝牙电梯。
     * <desc/>
     *
     * @param  projectId 项目编号
     * @return 0-禁用  1-启用
     * @author Juguang.S
     * @createDate 2018-04-09
     */
    @Override
    public Map<String,Integer> getIsCloudElevator(String projectId) throws Exception{
        return iOperateProjectDao.getIsCloudElevator(projectId);
    }

    /**
     * <desc>
     * 获取项目状态：1-启用，2-禁用
     * <desc/>
     *
     * @param projectId 项目编号
     * @return
     * @author Chunjian.G
     * @createDate 2017-12-01
     */
    @Override
    public Integer getProjectStatus(String projectId) throws Exception {
        Integer status = iOperateProjectDao.getProjectStatus(projectId);
        return status;
    }




    /**
     * <desc>
     *      获取项目列表。
     * <desc/>
     *
     * @param  projectName 项目编号
     * @return
     * @author shengen.T
     * @createDate 2018-01-12
     */
    @Override
    public List<OperateProjectInfoVO> getProjectInfoList(String projectName) throws Exception{
       return iOperateProjectDao.getProjectInfoList(projectName);
    }

    /**
     * <desc>
     * 获取项目所在省份/自治区/直辖市名称.
     * </desc>
     *
     * @param projectId 项目Id
     * @return 所在省份/自治区/直辖市名称
     * @author LewisLouis
     * @createDate 2018-01-27
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String getProjectCityName(String projectId) {
        return iOperateProjectDao.getProjectCityName(projectId);
    }

    /**
     * <desc>
     *      判断项目云设备状态是否为启用
     * </desc>
     *
     * @param projectId 项目id
     * @param type  设备类型 1云对讲 2云电梯
     * @return
     * @author Jiaqi.X
     * @createDate 2018/04/24
     */
    @Override
    public boolean checkProjectCloudDeviceStatus(String projectId,Integer type){
        Integer status = iOperateProjectDao.getCloudDeviceStatus(projectId,type);
        return status == 1;
    }

    /**
     * <desc>
     *      获取用户权限和项目信息相关字段，用于云电梯SDK上报设备信息变更后接口数据结构说明
     * </desc>
     *
     * @param projectId 项目id
     * @return 获取用户项目信息VO
     * @author wangzhi
     * @createDate 2019/01/21
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<PropertyRoleProjectGetVO> getRoleProjectInfo(String projectId) throws Exception {
        return iOperateProjectDao.getRoleProjectInfo(projectId);
    }

    /**
     * <desc>
     *      根据项目编号获取项目类型 住宅和办公。
     * <desc/>
     *
     * @param  projectId 项目编号
     * @return 项目类型
     * @author Juguang.S
     * @createDate 2019-08-14
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String getProjectType(String projectId) throws Exception {
        return iOperateProjectDao.getProjectType(projectId);
    }
    /**
     * <desc>
     *      分页查询通行方式
     * </desc>
     *
     * @param
     * @return  OperateProjectStatisticInfoVO
     * @Author Zhu.yj
     * @createDate  2019/10/28
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Map<String ,Object>> getPassTypePercent() throws Exception {
        // 查询一周内通行方式和对应记录数
        List<Map<String ,Object>> openTypeAndCount=iOperateProjectDao.getOperatePassTypeCount();
        int openCount = 0;
        List<Map<String, Object>> openData = new ArrayList<>();
        // 数字格式化对象
        NumberFormat numberFormat = NumberFormat.getPercentInstance();
        numberFormat.setMaximumFractionDigits(2);
        // 当前已计算百分比总和，记录前3百分比之和
        float presentValue = 0f;
        // 设置一个计数器
        int counter = 0;
        for (Map<String, Object> typeAndCountMap : openTypeAndCount) {
            counter ++;
            // 只计算3个类型
            if (openData.size() < 3) {
                String openType = typeAndCountMap.get("openType")+"";
                Integer count = Integer.parseInt(typeAndCountMap.get("count")+"");
                if (openType.equals("totalCount")) {
                    openCount = count;
                } else {
                    Map<String, Object> passMap = new HashMap<>();
                    // 计算百分比时要规避一个情况，因为四舍五入，则存在相加不等于1的情况，例如总数为3，3个数量分别为1,1,1，此时四舍五入计算百分比均为33.33%，再相加是99.99%，则显示有问题，最后一个应用1减，作为中和值
                    float passPercentValue;
                    // 通行类型大于3中的时候，直接计算，“其他”为中和值(查询数据中包括totalCount，判断大于4)；小于3种时的非最后一种也直接计算，最后一种中和
                    if (openTypeAndCount.size() > 4 || counter != openTypeAndCount.size()) {
                        passPercentValue = (float) count / (float) openCount ;
                        presentValue += passPercentValue;
                    } else {
                        passPercentValue = 1f - presentValue;
                    }
                    passMap.put("passName", OpenTypeEnum.getDescription(Integer.parseInt(openType)));
                    passMap.put("passPercent", numberFormat.format(passPercentValue));
                    openData.add(passMap);
                }
            }
        }
        // 库中通行类型大于3种，则存在其他，查询数据中包括totalCount，判断大于4
        if (openTypeAndCount.size() > 4) {
            Map<String, Object> passMap = new HashMap<>();
            passMap.put("passName", "其他");
            passMap.put("passPercent", numberFormat.format(1f - presentValue));
            openData.add(passMap);
        }


        return openData;
    }

    /**
     * <desc>
     *      获取城市项目占比排行
     * </desc>
     *
     * @param
     * @return
     * @Author Zhu.yj
     * @createDate  2019/10/31
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public OperateProjectStatisticInfoVO getCityProjectRank() throws Exception {
        OperateProjectStatisticInfoVO operateProjectStatisticInfoVO=new OperateProjectStatisticInfoVO();
        //获取城市项目占比排行
        List<Map<String ,Object>> projectCityAndCount=iOperateProjectDao.getOperateCityCount();
        List<Map<String ,Object>> cityProjectData=new ArrayList<>();
        NumberFormat numberFormat = NumberFormat.getPercentInstance();
        numberFormat.setMaximumFractionDigits(2);
        int cityProjectCount=0;
        //计算地址不为空的项目总数
        int currentProjectCount=0;
        float cityPercentValue=0f;
        int counter2 = 0;
        for(Map<String ,Object> projectCityAndCountMap:projectCityAndCount){
            counter2++;
            if (cityProjectData.size() < 10) {
                String cityName = StringHandlerUtil.getEmptyOrStringForObject(projectCityAndCountMap.get("addressName"));
                String position = projectCityAndCountMap.get("position") == null ?null: projectCityAndCountMap.get("position").toString();
                Integer count = Integer.parseInt(projectCityAndCountMap.get("count")+"");
                if (cityName.equals("totalCount")) {
                    cityProjectCount = count;
                } else if (cityName.equals("currentCount")) {
                    currentProjectCount = count;
                } else {
                    Map<String, Object> cityMap = new HashMap<>();
                    // 计算百分比时要规避一个情况，因为四舍五入，则存在相加不等于1的情况，例如总数为3，3个数量分别为1,1,1，此时四舍五入计算百分比均为33.33%，再相加是99.99%，则显示有问题，最后一个应用1减，作为中和值
                    float tempCityPercentValue;
                    if (projectCityAndCount.size() > 12 || counter2 != projectCityAndCount.size() + 1) {
                        tempCityPercentValue = (float) count / (float) cityProjectCount;
                        cityPercentValue += tempCityPercentValue;
                    } else {
                        tempCityPercentValue = (currentProjectCount / cityProjectCount) - cityPercentValue;
                    }
                    cityMap.put("cityName", cityName);
                    cityMap.put("position", position);
                    cityMap.put("count", count);
                    cityMap.put("cityPercent", numberFormat.format(tempCityPercentValue));
                    cityProjectData.add(cityMap);
                }
            }
        }
        operateProjectStatisticInfoVO.setCityProjectRankList(cityProjectData);
        operateProjectStatisticInfoVO.setProjectCount(cityProjectCount+"");
        return operateProjectStatisticInfoVO;
    }

    /**
     * <desc>
     * 获取可用最小项目编号值
     * </desc>
     *
     * @return
     * @Author caoshuai
     * @createDate 2020/09/16
     */
    @Override
    public String getMinProjectId() {

        return iOperateProjectDao.getMinProjectId();
    }

    /**
     * <desc>
     * RobotGo调试工具获取项目下的开发者用户的 机器人设备授权状态和机器人白名单授权状态
     * </desc>
     *
     * @param projectId
     * @param userId
     * @Author chengshican
     * @Date 2020-09-17 17:00
     * @Param
     * @Return
     * @Exception
     */
    @Override
    public Map<String, Object> getRobotGoProjectWhitelistAndDeviceAuthStatusByUserId(String projectId, String userId) throws Exception {
        return iOperateProjectDao.getRobotGoProjectWhitelistAndDeviceAuthStatusByUserId(projectId, userId);
    }

    /**
     * <desc>
     * 获取证书详情
     * </desc>
     *
     * @param operateLicenseDTO 查询参数DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/17
     */
    @Override
    public OperateLicenseAllInfoVO getLicenseDetail(OperateLicenseDTO operateLicenseDTO) throws Exception {
        Map<String, Object> params = new HashMap<>();
        OperateProjectDetailVO projectDetailVO = iOperateProjectDao.getDetail(operateLicenseDTO.getProjectId());
        Integer linceseNo = iOperateProjectDao.getMaxLicenseNo(operateLicenseDTO.getProjectId());
        params.put("projectId", operateLicenseDTO.getProjectId());
        params.put("licenseNo", linceseNo);
        List<OperateLicenseDetailVO> operateLicenseDetailVOS = iOperateProjectDao.getAllLicenseDetailVO(params);
        OperateLicenseAllInfoVO operateLicenseAllInfoVO = new OperateLicenseAllInfoVO();
        operateLicenseAllInfoVO.setOperateLicenseDetailVOS(operateLicenseDetailVOS);
        operateLicenseAllInfoVO.setProjectId(projectDetailVO.getProjectId());
        operateLicenseAllInfoVO.setProjectName(projectDetailVO.getProjectName());
        operateLicenseAllInfoVO.setPcMaxCount(projectDetailVO.getPcMaxCount());
        return operateLicenseAllInfoVO;
    }

    /**
     * <desc>
     *      修改特征码状态
     * </desc>
     *
     * @param operateLicenseDTO 查询参数DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/17
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Integer updatePCStatus(OperateLicenseDTO operateLicenseDTO) throws Exception {
        Date nowTime = new Date();
        Map<String, Object> params = new HashMap<>();
        //根据特征码查询证书
        ProjectLicensePO po = iOperateProjectDao.getLicense(operateLicenseDTO.getProjectId());
        //根据旧证书创建一个新证书，证书信息与旧证书一致，只是licenseNo加1
        ProjectLicensePO newPO = new ProjectLicensePO();
        BeanUtils.copyProperties(po, newPO);
        JSONObject jsonObject = JSONObject.parseObject(po.getLicenseInfo());
        JSONObject licenseInfo = jsonObject.getJSONObject("licenseInfo");
        licenseInfo.put("licenseNo", po.getLicenseNo() + 1);
        jsonObject.put("licenseInfo", licenseInfo);
        newPO.setLicenseInfo(jsonObject.toJSONString());
        newPO.setLicenseId(LogicIdUtil.bussinessId());
        newPO.setLicenseNo(po.getLicenseNo() + 1);
        newPO.setCreateUserId(operateLicenseDTO.getLoginUserId());
        newPO.setOperateUserId(operateLicenseDTO.getLoginUserId());
        newPO.setStatus(DataStatusEnum.NORMAL.getType());
        newPO.setCreateTime(nowTime);
        newPO.setUpdateTime(nowTime);
        iOperateProjectDao.save(SqlUtil.durableData(newPO, PlatformConstants.TABLE_SAVE));
        //修改特征码信息
        LicenseUsagePO usagePO = iOperateProjectDao.getPCInfo(po.getProjectId());
        List<String> pcInfoList = StringHandlerUtil.splitStringList(usagePO.getPcInfo());
        //去重
        Set<String> pcInfoSet = new HashSet<>(pcInfoList);
        if (DataStatusEnum.NORMAL.getType().equals(operateLicenseDTO.getStatus())){
            pcInfoSet.add(operateLicenseDTO.getPcInfo());
        }
        if(DataStatusEnum.BAN.getType().equals(operateLicenseDTO.getStatus())){
            pcInfoSet.remove(operateLicenseDTO.getPcInfo());
        }
        usagePO.setPcInfo(StringUtils.join(pcInfoSet,","));
        usagePO.setUsageId(LogicIdUtil.bussinessId());
        usagePO.setLicenseId(newPO.getLicenseId());
        usagePO.setLicenseNo(newPO.getLicenseNo());
        usagePO.setStatus(DataStatusEnum.NORMAL.getType());
        usagePO.setUseTime(nowTime);
        usagePO.setCreateUserId(operateLicenseDTO.getLoginUserId());
        usagePO.setOperateUserId(operateLicenseDTO.getLoginUserId());
        usagePO.setCreateTime(nowTime);
        usagePO.setUpdateTime(nowTime);
        iOperateProjectDao.save(SqlUtil.durableData(usagePO, PlatformConstants.TABLE_SAVE));
        //修改项目与特征码对应记录表中该特征码的状态
        params.put("pcInfo", operateLicenseDTO.getPcInfo());
        params.put("projectId", operateLicenseDTO.getProjectId());
        params.put("operateUserId", operateLicenseDTO.getLoginUserId());
        params.put("updateTime", nowTime);
        params.put("status", operateLicenseDTO.getStatus());
        iOperateProjectDao.updateProjectPcInfo(params);
        //记录操作日志
        OperateUserInfoPO operateUserInfoPO = iOperateProjectDao.getUserInfo(operateLicenseDTO.getLoginUserId());
        OperationSpecialLogPO operationSpecialLogPO = handleSaveOperationLog(operateUserInfoPO);
//        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
//        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
//        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
//        operationSpecialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
        operationSpecialLogPO.setOuterId(operateLicenseDTO.getProjectId());
        operationSpecialLogPO.setIp(operateLicenseDTO.getIp());
        operationSpecialLogPO.setOperateFunction(operateLicenseDTO.getOperateFunction());
        operationSpecialLogPO.setOperateWay(operateLicenseDTO.getOperateWay());
        operationSpecialLogPO.setOperateData(JSON.toJSONString(operateLicenseDTO));
        operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + operateLicenseDTO.getStatusString() + "电脑授权码服务器云端证书，电脑授权码为：" + operateLicenseDTO.getPcInfo() + "，ip为：" + operateLicenseDTO.getIp() + "，项目id为：" + operateLicenseDTO.getProjectId());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(nowTime);
        operationSpecialLogPO.setUpdateTime(nowTime);
        iOperateProjectDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));
        return 1;
    }

    /**
     * <desc>
     *      获取日志分页列表
     * </desc>
     *
     * @param operateLicenseDTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/18
     */
    @Override
    public Page<OperateProjectLogPageVO> getLogPage(OperateLicenseDTO operateLicenseDTO) throws Exception {
        if (StringUtils.isBlank(operateLicenseDTO.getOrderColumn()) || StringUtils.isBlank(operateLicenseDTO.getOrderRule())){
            operateLicenseDTO.setOrderColumn("createTime");
            operateLicenseDTO.setOrderRule("DESC");
        }
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(operateLicenseDTO);
        Page<OperateProjectLogPageVO> page = new Page<>();
        page.getPage().setCurrentPage(operateLicenseDTO.getCurrentPage());
        page.getPage().setPageSize(operateLicenseDTO.getPageSize());
        params.put("pageSize", page.getPage().getPageSize());
        params.put("startSlip", page.getPage().getStartSlip());
        page.setRows(iOperateProjectDao.getLogPage(params), iOperateProjectDao.getLogPageCount(params));
        return page;
    }

    /**
     * <desc>
     *      保存电脑特征码
     * </desc>
     *
     * @param operateLicenseDTO 证书管理DTO
     * @return 受影响行数
     * @Author Zhu.yj
     * @createDate  2020/9/18
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public MessageVO savePcInfo(OperateLicenseDTO operateLicenseDTO) throws Exception {
        String operateUserId = StringUtils.isBlank(operateLicenseDTO.getLoginUserId()) ? operateLicenseDTO.getIp() : operateLicenseDTO.getLoginUserId();
        SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        Date nowTime = new Date();
        Integer maxLicenseNo = iOperateProjectDao.getMaxLicenseNo(operateLicenseDTO.getProjectId());
        if (maxLicenseNo == null){//项目下无证书
            return new MessageVO(OperateErrorCodeEnum.OPERATE_NONE_LICENSE_ERROR.getErrorCode());
        }
        OperateProjectDetailVO detailVO = iOperateProjectDao.getDetail(operateLicenseDTO.getProjectId());
        //获取该项目下所有的特征码，包括被禁用的（为了兼容线下平台数据，此处新增一张表用来记录该项目曾经添加过的特征码）
        List<String> pcInfoAllList = iOperateProjectDao.getAllPcInfo(operateLicenseDTO.getProjectId());
        //判断项目下可用特征码
        if (pcInfoAllList.size() == detailVO.getPcMaxCount()){
            //在线添加和人工添加返回错误码不一致 1为在线添加
            if (operateLicenseDTO.getSource() == 1){
                return new MessageVO(OperateErrorCodeEnum.OPERATE_OUT_OF_MAX_PC_COUNT_ERR.getErrorCode());
            }
            ErrorCode errorCode = OperateErrorCodeEnum.OPERATE_OUT_OF_MAX_AUTH_COUNT_ERR.getErrorCode();
            return new MessageVO(errorCode, String.format(errorCode.getCodeMsg(), detailVO.getPcMaxCount()));
        }
        if (pcInfoAllList.contains(operateLicenseDTO.getPcInfo())){
            return new MessageVO(OperateErrorCodeEnum.OPERATE_PC_INFO_EXIST_ERR.getErrorCode());
        }
        ProjectLicensePO projectLicensePO  = iOperateProjectDao.getLicense(operateLicenseDTO.getProjectId());
        //生成新证书，licenseNo+1 其它不变
        JSONObject jsonObject = JSONObject.parseObject(projectLicensePO.getLicenseInfo());
        JSONObject licenseInfo = jsonObject.getJSONObject("licenseInfo");
        licenseInfo.put("licenseNo", maxLicenseNo + 1);
        jsonObject.put("licenseInfo", licenseInfo);
        projectLicensePO.setLicenseInfo(jsonObject.toJSONString());
        projectLicensePO.setLicenseId(LogicIdUtil.bussinessId());
        projectLicensePO.setLicenseNo(maxLicenseNo + 1);
        projectLicensePO.setCreateTime(nowTime);
        projectLicensePO.setUpdateTime(nowTime);
        projectLicensePO.setStatus(DataStatusEnum.NORMAL.getType());
        projectLicensePO.setCreateUserId(operateLicenseDTO.getLoginUserId());
        projectLicensePO.setOperateUserId(operateLicenseDTO.getLoginUserId());
        iOperateProjectDao.save(SqlUtil.durableData(projectLicensePO, PlatformConstants.TABLE_SAVE));
        //根据项目id找出该项目中licenseNO最大的特征码
        LicenseUsagePO usagePO = iOperateProjectDao.getPCInfo(operateLicenseDTO.getProjectId());
        //生成新特征码
        if (usagePO == null){
            usagePO = new LicenseUsagePO();
        }
        if (usagePO.getUseTime() == null){
            usagePO.setUseTime(nowTime);
        }
        if (StringUtils.isNotBlank(usagePO.getPcInfo())){
            usagePO.setPcInfo(String.format("%s,%s",usagePO.getPcInfo(), operateLicenseDTO.getPcInfo()));
        }else {
            usagePO.setPcInfo(operateLicenseDTO.getPcInfo());
        }
        usagePO.setLicenseNo(maxLicenseNo + 1);
        usagePO.setLicenseId(projectLicensePO.getLicenseId());
        usagePO.setUsageId(LogicIdUtil.bussinessId());
        usagePO.setProjectId(operateLicenseDTO.getProjectId());
        usagePO.setCreateTime(nowTime);
        usagePO.setUpdateTime(nowTime);
        usagePO.setStatus(DataStatusEnum.NORMAL.getType());
        usagePO.setCreateUserId(operateUserId);
        usagePO.setOperateUserId(operateUserId);
        Integer result =  iOperateProjectDao.save(SqlUtil.durableData(usagePO, PlatformConstants.TABLE_SAVE));
        //将添加的改特征码添加到项目与特征码对应记录表中
        ProjectPcInfoRecordPO projectPcInfoRecordPO = new ProjectPcInfoRecordPO();
        projectPcInfoRecordPO.setRecordId(LogicIdUtil.bussinessId());
        projectPcInfoRecordPO.setProjectId(operateLicenseDTO.getProjectId());
        projectPcInfoRecordPO.setPcInfo(operateLicenseDTO.getPcInfo());
        projectPcInfoRecordPO.setSource(operateLicenseDTO.getSource());
        projectPcInfoRecordPO.setUseTime(nowTime);
        projectPcInfoRecordPO.setCreateUserId(operateLicenseDTO.getLoginUserId());
        projectPcInfoRecordPO.setOperateUserId(operateLicenseDTO.getLoginUserId());
        projectPcInfoRecordPO.setStatus(DataStatusEnum.NORMAL.getType());
        projectPcInfoRecordPO.setCreateTime(nowTime);
        projectPcInfoRecordPO.setUpdateTime(nowTime);
        iOperateProjectDao.save(SqlUtil.durableData(projectPcInfoRecordPO, PlatformConstants.TABLE_SAVE));

        //记录特殊操作日志
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        if(StringUtils.isNotBlank(operateLicenseDTO.getLoginUserId())){
            OperateUserInfoPO operateUserInfoPO = iOperateProjectDao.getUserInfo(operateLicenseDTO.getLoginUserId());
            operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
            operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        }else {
            operationSpecialLogPO.setAccount(operateLicenseDTO.getIp());
            operationSpecialLogPO.setRealName(operateLicenseDTO.getIp());
        }
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setOuterId(operateLicenseDTO.getProjectId());
        operationSpecialLogPO.setIp(operateLicenseDTO.getIp());
        operationSpecialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
        operationSpecialLogPO.setOperateFunction(operateLicenseDTO.getOperateFunction());
        operationSpecialLogPO.setOperateWay(operateLicenseDTO.getOperateWay());
        operationSpecialLogPO.setOperateData(JSON.toJSONString(operateLicenseDTO));
        operationSpecialLogPO.setOperateDec(operationSpecialLogPO.getRealName() + "于" +dateFormat.format(nowTime)+ "通过"+  operateLicenseDTO.getSourceString() +"在" + operateLicenseDTO.getProjectId() + "项目添加电脑特征码，电脑特征码为" + operateLicenseDTO.getPcInfo());
        operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
        operationSpecialLogPO.setCreateTime(nowTime);
        operationSpecialLogPO.setUpdateTime(nowTime);
        iOperateProjectDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));
        //在线添加证书
        if (operateLicenseDTO.getSource() == 1){
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("pcInfoList", StringHandlerUtil.splitStringList(usagePO.getPcInfo()));
           return new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode(), resultMap);
        }
        return new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode());
    }

    /**
     * <desc>
     *      获取证书
     * </desc>
     *
     * @param operateLicenseDTO 参数DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/24
     */
    @Override
    public Map<String, Object> getCertificate(OperateLicenseDTO operateLicenseDTO) throws Exception {
        Date nowTime = new Date();
        Map<String, Object> resultMap = this.assembleLicense(operateLicenseDTO.getProjectId(), LicenseTypeEnum.FORMAL_LICENSE.getType());
        // 更新证书最近使用时间
        if (operateLicenseDTO.getPcInfo() != null) {
            Map<String, Object> params = new HashMap<>();
            params.put("pcInfo", operateLicenseDTO.getPcInfo());
            params.put("useTime", nowTime);
            params.put("updateTime", nowTime);
            params.put("userId", "smartCard");
            iOperateProjectDao.updatePcInfo(params);
            //当用户id不为空时，表示运营导出，添加操作日志
        } else if (operateLicenseDTO.getLoginUserId() != null) {
            OperateUserInfoPO operateUserInfoPO = iOperateProjectDao.getUserInfo(operateLicenseDTO.getLoginUserId());
            OperationSpecialLogPO operationSpecialLogPO = handleSaveOperationLog(operateUserInfoPO);
//            operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
//            operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
//            operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
//            operationSpecialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
            operationSpecialLogPO.setOuterId(operateLicenseDTO.getProjectId());
            operationSpecialLogPO.setIp(operateLicenseDTO.getIp());
            operationSpecialLogPO.setOperateFunction(operateLicenseDTO.getOperateFunction());
            operationSpecialLogPO.setOperateWay(operateLicenseDTO.getOperateWay());
            operationSpecialLogPO.setOperateData(JSON.toJSONString(operateLicenseDTO));
            operationSpecialLogPO.setOperateDec(operateUserInfoPO.getRealName() + "导出证书信息");
            operationSpecialLogPO.setStatus(DataStatusEnum.NORMAL.getType());
            operationSpecialLogPO.setCreateTime(nowTime);
            operationSpecialLogPO.setUpdateTime(nowTime);
            iOperateProjectDao.save(SqlUtil.durableData(operationSpecialLogPO, PlatformConstants.TABLE_SAVE));
        }
        return resultMap;
    }

    /**
     * <desc>
     *      在线查询证书
     * </desc>
     *
     * @param operateLicenseDTO 证书管理DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/25
     */
    @Override
    public OperateOnlineLicenseInfoVO getLicense(OperateLicenseDTO operateLicenseDTO) throws Exception {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        SimpleDateFormat dateFormat1 = new SimpleDateFormat(DateUtil.YMDSQL);
        SimpleDateFormat dateFormat2 = new SimpleDateFormat(DateUtil.YYYYMMDD);
        Date nowTime = new Date();
        Map<String, Object> params = new HashMap<>();
        Integer maxLicenseNo = iOperateProjectDao.getMaxLicenseNo(operateLicenseDTO.getProjectId());
        params.put("projectId", operateLicenseDTO.getProjectId());
        params.put("licenseNo", maxLicenseNo);
        params.put("securityCode", operateLicenseDTO.getSecurityCode());
        OperateOnlineLicenseInfoVO licenseInfoVO = iOperateProjectDao.getLicenseInfo(params);
            if (licenseInfoVO == null || licenseInfoVO.getLicenseInfo() == null) {
            return licenseInfoVO;
        }
        JSONObject jsonObject = JSONObject.parseObject(licenseInfoVO.getLicenseInfo());
        List<OperateSystemAuthInfoVO> systemAuthInfoVOList = JSONArray.parseArray(JSONObject.toJSONString(jsonObject.get("systemAuth")), OperateSystemAuthInfoVO.class);
        if (systemAuthInfoVOList != null && !systemAuthInfoVOList.isEmpty()) {
            for (OperateSystemAuthInfoVO authInfoVO : systemAuthInfoVOList) {
                //此处只需要把yyyyMMdd（包含yyyy-MM-dd）格式的日期字符串转换为yyyy-MM-dd
                if (authInfoVO.getEndDate() != null && !authInfoVO.getEndDate().equals("FFFFFFFF") && !authInfoVO.getEndDate().contains("-")){
                    authInfoVO.setEndDate(dateFormat1.format(dateFormat2.parse(authInfoVO.getEndDate())));
                }

                //拼接权限
                if (authInfoVO.getSysType().equals(PropertyEquipTypeEnum.ELEVATOR.getType())) {
                    licenseInfoVO.setElevatorAuthTime(authInfoVO.getEndDate());
                } else if (authInfoVO.getSysType().equals(PropertyEquipTypeEnum.ENTRANCE.getType())) {
                    licenseInfoVO.setEntranceAuthTime(authInfoVO.getEndDate());
                }
            }
        }
        List<String> pcInfoList = iOperateProjectDao.getAllPcInfo(operateLicenseDTO.getProjectId());
        licenseInfoVO.setPcInfoList(pcInfoList);
        if (StringUtils.isNotBlank(operateLicenseDTO.getOperateFunction()) && StringUtils.isNotBlank(operateLicenseDTO.getOperateWay())) {
            OperationSpecialLogPO specialLogPO = new OperationSpecialLogPO();
            specialLogPO.setLogId(LogicIdUtil.bussinessId());
            specialLogPO.setIp(operateLicenseDTO.getIp());
            specialLogPO.setOperateData(JsonUtil.toJSON(operateLicenseDTO));
            specialLogPO.setOuterId(operateLicenseDTO.getProjectId());
            specialLogPO.setOperateFunction(operateLicenseDTO.getOperateFunction());
            specialLogPO.setOperateWay(operateLicenseDTO.getOperateWay());
            specialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
            specialLogPO.setOperateDec(operateLicenseDTO.getIp() + "于" + dateFormat.format(nowTime) + "通过在线获取方式查询证书信息");
            specialLogPO.setCreateTime(nowTime);
            specialLogPO.setUpdateTime(nowTime);
            specialLogPO.setRealName(operateLicenseDTO.getIp());
            iOperateProjectDao.save(SqlUtil.durableData(specialLogPO, PlatformConstants.TABLE_SAVE));
        }
        return licenseInfoVO;
    }

    /**
     * <desc>
     *  同步ProjectInfo到线下平台
     * <desc/>
     *
     * @param nowDate 当前时间
     * @param projectPO 项目信息
     * @return
     * @author caoshuai
     * @createDate 2020-09-23
     */
    private boolean pushProjectInfoToOffline(int operationType, Date nowDate, ProjectPO projectPO) {


        String url;
        Map<String, Object> resultMap;
        if (operationType == SAVE_OPERATION) {
            url = offlinePLatformDomain + PlatformConstants.OFFLINE_PLATFORM_API_ADD_PROJECT_INFO;
            Map<String, Object> paramMap = handleParams(projectPO);
            paramMap.put("token", offlinePlatformToken);
            String result = HttpsPost.doPost(url, paramMap, 20000, 20000);
            resultMap = JSONObject.parseObject(result, HashMap.class);
        } else {
            url = offlinePLatformDomain  + PlatformConstants.OFFLINE_PLATFORM_EDIT_PROJECT_INFO;
            Map<String, Object> paramMap = handleParams(projectPO);
            SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            paramMap.put("lastModifyTime", dateFormat.format(nowDate));
            paramMap.put("token", offlinePlatformToken);

            String result = HttpsPost.doPost(url, paramMap, 20000, 20000);
            resultMap = JSONObject.parseObject(result, HashMap.class);
        }

        if ("0".equals(resultMap.get("code") + "")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     *  <desc>
     *   下载证书
     * </desc>
     *
     * @param operateLicenseDTO 证书管理DTO
     * @return 证书加密字符串
     * @Author Zhu.yj
     * @createDate  2020/9/27
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Map<String, Object> licenseDownload(OperateLicenseDTO operateLicenseDTO) throws Exception {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtil.DATE_FORMAT_TYPE1);
        Date nowTime = new Date();
        Map<String, Object> resultMap = this.assembleLicense(operateLicenseDTO.getProjectId(), operateLicenseDTO.getLicenseType());
        if (resultMap == null) {
            return null;
        }
        resultMap.remove("licenseNo");
        // 保存特殊操作日志
        OperationSpecialLogPO specialLogPO = new OperationSpecialLogPO();
        //记录人工导出时的日志
        if (StringUtils.isNotBlank(operateLicenseDTO.getLoginUserId())){
            OperateUserInfoPO operateUserInfoPO = iOperateProjectDao.getUserInfo(operateLicenseDTO.getLoginUserId());
            specialLogPO.setRealName(operateUserInfoPO.getRealName());
            specialLogPO.setAccount(operateUserInfoPO.getUserName());
            specialLogPO.setOperateDec(operateUserInfoPO.getRealName() + "于" + dateFormat.format(nowTime) +"导出"+ LicenseTypeEnum.getDescriptionByType(operateLicenseDTO.getLicenseType()) + "证书信息");
        }
        else {
            specialLogPO.setOperateDec(operateLicenseDTO.getIp() + "于" + dateFormat.format(nowTime) + "通过证书网站下载" + LicenseTypeEnum.getDescriptionByType(operateLicenseDTO.getLicenseType()) + "证书信息");
            specialLogPO.setRealName(operateLicenseDTO.getIp());
        }
        specialLogPO.setLogId(LogicIdUtil.bussinessId());
        specialLogPO.setIp(operateLicenseDTO.getIp());
        specialLogPO.setOperateData(JsonUtil.toJSON(operateLicenseDTO));
        specialLogPO.setOuterId(operateLicenseDTO.getProjectId());
        specialLogPO.setOperateFunction(operateLicenseDTO.getOperateFunction());
        specialLogPO.setOperateWay(operateLicenseDTO.getOperateWay());
        specialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
        specialLogPO.setCreateTime(nowTime);
        specialLogPO.setUpdateTime(nowTime);
        iOperateProjectDao.save(SqlUtil.durableData(specialLogPO, PlatformConstants.TABLE_SAVE));
        return resultMap;
    }

    /**
     * <desc>
     *  处理线下平台入参
     * <desc/>
     *
     * @param projectPO 项目信息
     * @return
     * @author caoshuai
     * @createDate 2020/09/27
     */
    private HashMap<String, Object> handleParams (ProjectPO projectPO){
        HashMap<String, Object> paramMap = new HashMap<>();
        if( projectPO.getProjectId() != null){
            paramMap.put("projectId", projectPO.getProjectId());
        }
        if(projectPO.getProjectName() != null){
            paramMap.put("projectName", projectPO.getProjectName());
        }
        if( projectPO.getCustomerName() != null){
            paramMap.put("customerName", projectPO.getCustomerName());
        }
        if( projectPO.getProjectMemo() != null){
            paramMap.put("projectMemo", projectPO.getProjectMemo());
        }
        if( projectPO.getProjectSystem() != null){
            paramMap.put("cloudStatus", projectPO.getProjectSystem().contains("1") ? "0" : "1");
        }
        if( projectPO.getProjectFile() != null){
            paramMap.put("projectFile", projectPO.getProjectFile());
        }
        if( projectPO.getProvinceId() != null){
            paramMap.put("provinceInfo", iOperateProjectDao.getAddressById(projectPO.getProvinceId()));
        }
        if( projectPO.getCityId() != null){
            paramMap.put("cityInfo", iOperateProjectDao.getAddressById(projectPO.getCityId()));
        }
        if( projectPO.getCountryId() != null){
            paramMap.put("countyInfo", iOperateProjectDao.getAddressById(projectPO.getCountryId()));
        }
        if( projectPO.getProductType() != null){
            //线下平台无0 的情况 为兼容线下平台当为0时 给类型为1
            if (projectPO.getProductType() == 0){
                paramMap.put("productType", 1);
            }else {
                paramMap.put("productType", projectPO.getProductType());
            }

        }
        if( projectPO.getPcMaxCount()!= null){
            paramMap.put("pcMaxCount", projectPO.getPcMaxCount());
        }
        if( projectPO.getProjectProperty() != null){
            paramMap.put("projectProperty", projectPO.getProjectProperty());
        }
        return paramMap;
    }

    /**
     * <desc>
     * 同步ProjectKey到线下平台
     * <desc/>
     *
     * @param createTime 创建时间
     * @param projectPO 项目信息
     * @return
     * @author caoshuai
     * @createDate 2020-09-23
     */
    private boolean pushProjectKeyToOffline(Date createTime, ProjectPO projectPO){
        String url  = offlinePLatformDomain  + PlatformConstants.OFFLINE_PLATFORM_ADD_PROJECT_KEY;
        Map<String, Object> params = new HashMap();
        params.put("projectId", projectPO.getProjectId());
        params.put("authKind", "4");
        params.put("sysType", "1");
        params.put("keyKind", "0x01");
        params.put("keyType", "2");
        params.put("keyVersion", "1");

        params.put("keyValue", projectPO.getPubKey());
        params.put("extraInfo", String.valueOf(Math.random()).substring(2,6));
        SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        params.put("createTime", dateFormat.format(createTime));
        params.put("token", offlinePlatformToken);

        String result = HttpsPost.doPost(url, params, 20000, 20000);

        if (StringUtils.isBlank(result)) {
            return false;
        }
        Map<String, Object> resultMap = JSONObject.parseObject(result, HashMap.class);
        if ("0".equals(resultMap.get("code") + "")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     *  <desc>
     *      获取特征码信息列表
     * </desc>
     *
     * @param operateLicenseDTO 证书管理DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/27
     */
    @Override
    public List<String> getPcInfoList(OperateLicenseDTO operateLicenseDTO) throws Exception {
        LicenseUsagePO licenseUsagePO =  iOperateProjectDao.getPCInfo(operateLicenseDTO.getProjectId());
        if (licenseUsagePO != null){
            return StringHandlerUtil.splitStringList(licenseUsagePO.getPcInfo());
        }
        return null;
    }


    /**
     * <desc>
     *      同步项目与特征码对应记录表数据()
     * </desc>
     *
     * @Author Zhu.yj
     * @createDate  2020/10/13
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Integer synchronizeData() throws Exception {
        List<ProjectPcInfoRecordPO> pcInfoRecordPOList = new ArrayList<>();
        Date nowTime = new Date();
        Integer rowCount = iOperateProjectDao.getProjectPcInfoRecordCount();
        if (rowCount != null && rowCount > 0){
            return -OperateErrorCodeEnum.OPERATE_SYNC_DATA_EXIST_ERR.getCode();
        }
        List<Map<String, Object>> pcInfoMapList = iOperateProjectDao.getSynchronizeData();
        for (Map<String, Object> pcInfoMap : pcInfoMapList){
            List<String> pcInfoList = StringHandlerUtil.splitStringList(pcInfoMap.get("pcInfo").toString());
            Set<String> pcInfoSet = new HashSet<>(pcInfoList);
            for (String pcInfo : pcInfoSet){
                ProjectPcInfoRecordPO pcInfoRecordPO = new ProjectPcInfoRecordPO();
                pcInfoRecordPO.setRecordId(LogicIdUtil.bussinessId());
                pcInfoRecordPO.setProjectId(pcInfoMap.get("projectId").toString());
                pcInfoRecordPO.setPcInfo(pcInfo);
                pcInfoRecordPO.setUseTime(nowTime);
                //同步旧数据时来源默认人工添加 1在线获取 2人工添加
                pcInfoRecordPO.setSource(2);
                pcInfoRecordPO.setCreateUserId("synchronize");
                pcInfoRecordPO.setOperateUserId("synchronize");
                pcInfoRecordPO.setStatus(DataStatusEnum.NORMAL.getType());
                pcInfoRecordPO.setCreateTime(nowTime);
                pcInfoRecordPO.setUpdateTime(nowTime);
                pcInfoRecordPOList.add(pcInfoRecordPO);
            }
        }
        return iOperateProjectDao.batchSaveProjectPcInfoRecord(pcInfoRecordPOList);
    }

    @Override
    public Integer getCountBySceneId(String sceneId) {
        return iOperateProjectDao.getCountBySceneId(sceneId);
    }

    /**
     * <desc>
     *      获取用户角色组列表
     * </desc>
     *
     * @param projectId
     * @return
     * @Author Zhu.yj
     * @createDate  2021/4/19
     */
    @Override
    public List<Map<String, Object>> getUserRoleList(String projectId) throws Exception {
        return iOperateProjectDao.getUserRoleList(projectId);
    }

    /**
     * <desc>
     *      获取项目下的楼栋、单元房间列表
     * </desc>
     *
     * @param projectId 项目id
     * @return
     * @Author Zhu.yj
     * @createDate  2021/4/19
     */
    @Override
    public List<PropertyTreeMenuVO> getBuildList(String projectId) throws Exception {
        return iOperateProjectDao.getBuildUnitRoomList(projectId);
    }

    /**
     * <desc>
     *      组装证书信息
     * </desc>
     *
     * @param  projectId 项目id
     * @param licenseType 证书类型 1正式证书 2工程证书
     * @return
     * @Author Zhu.yj
     * @createDate  2020/9/27
     */
    private Map<String, Object> assembleLicense(String projectId, Integer licenseType) {
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> pcMapList = new ArrayList<>();
        ProjectLicensePO projectLicensePO = iOperateProjectDao.getLicense(projectId);
        if (projectLicensePO == null || StringUtils.isBlank(projectLicensePO.getLicenseInfo())) {
            return null;
        }
        String licenseInfo = projectLicensePO.getLicenseInfo();
        String licenseNo = projectLicensePO.getLicenseNo().toString();
        /* *
         * productType 0旺龙非集团 1旺龙集团，因线下平台不识别0，所以即使后台中中此字段为0，
           拼接证书时此字段依旧传1，集团或非集团项目只在云平台区分
         * */
        JSONObject jsonObject = JSONObject.parseObject(licenseInfo);
        if (jsonObject == null){
            return null;
        }
        JSONObject productConfig = jsonObject.getJSONObject("productConfig");
        if (productConfig!= null && productConfig.get("productType") != null && (Integer) productConfig.get("productType") == 0){
            productConfig.put("productType", 1);
            jsonObject.put("productConfig", productConfig);
        }

        //当下载工程证书时
        if (LicenseTypeEnum.ENGINEER_LICENSE.getType().equals(licenseType)) {
            //工程证书不拼接特征码，只设置过期时间
            jsonObject.put("licenseType", LicenseTypeEnum.ENGINEER_LICENSE.getType());
            jsonObject.put("availableDays", ENGINEER_LICENSE_AVAILABLE_DAYS);
            // 创建项目下的工程证书，工程证书的licenseNO为0
        } else if (LicenseTypeEnum.FORMAL_LICENSE.getType().equals(licenseType)) {
            //正式证书拼接特征码
            LicenseUsagePO usagePOS = iOperateProjectDao.getPCInfo( projectLicensePO.getProjectId());
            if(usagePOS == null){
                return null;
            }
            List<String> pcInfoList = StringHandlerUtil.splitStringList(usagePOS.getPcInfo());
            for (String pcInfo : pcInfoList){
                Map<String, Object> pcInfoMap = new HashMap<>();
                pcInfoMap.put("pcUuid", pcInfo);
                pcMapList.add(pcInfoMap);
            }
            jsonObject.put("licenseType", LicenseTypeEnum.FORMAL_LICENSE.getType());
            jsonObject.put("bindServerPC", pcMapList);
        }
        resultMap.put("licenseNo", licenseNo);
        resultMap.put("certificateInfo", SmartCardEncryptUtil.LicenseEncrypt(jsonObject.toJSONString()));
        return resultMap;
    }

    private OperationSpecialLogPO handleSaveOperationLog(OperateUserInfoPO operateUserInfoPO ){
        OperationSpecialLogPO operationSpecialLogPO = new OperationSpecialLogPO();
        operationSpecialLogPO.setLogId(LogicIdUtil.bussinessId());
        operationSpecialLogPO.setAccount(operateUserInfoPO.getUserName());
        operationSpecialLogPO.setRealName(operateUserInfoPO.getRealName());
        operationSpecialLogPO.setFunctionType(LogFunctionTypeEnum.PROJECT_LOG.getType());
        return operationSpecialLogPO;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Object timeTaskDevicePassRecordLatestSave(String startTime1, String endTime1, String startTime2, String endTime2) {
        iOperateProjectDao.deleteByRangeDateTime(startTime1, endTime1);
        iOperateProjectDao.insertByRangeDateTime(startTime2, endTime2);
        return "ok";
    }

}
